bill 2 years ago
commit a8ee574ffc

@ -16,7 +16,7 @@ RUN git clone https://github.com/sunyinqi0508/AQuery2
RUN python3 -m pip install -r AQuery2/requirements.txt RUN python3 -m pip install -r AQuery2/requirements.txt
ENV IS_DOCKER_IMAGE=1 CXX=clang-14 ENV IS_DOCKER_IMAGE=1 CXX=clang++-14
CMD cd AQuery2 && python3 prompt.py CMD cd AQuery2 && python3 prompt.py

@ -97,6 +97,6 @@ docker:
docker build -t aquery . docker build -t aquery .
clean: clean:
rm *.shm *.o dll.so server.so server.bin libaquery.a libaquery.lib -rf 2> $(NULL_DEVICE) || true rm .cached *.shm *.o dll.so server.so server.bin libaquery.a libaquery.lib -rf 2> $(NULL_DEVICE) || true

@ -4,6 +4,92 @@
AQuery++ Database is a cross-platform, In-Memory Column-Store Database that incorporates compiled query execution. AQuery++ Database is a cross-platform, In-Memory Column-Store Database that incorporates compiled query execution.
## Requirements
1. Recent version of Linux, Windows or MacOS, with recent C++ compiler that has C++17 (1z) support. (however c++20 is recommended if available for heterogeneous lookup on unordered containers)
- GCC: 9.0 or above (g++ 7.x, 8.x fail to handle fold-expressions due to a compiler bug)
- Clang: 5.0 or above (Recommended)
- MSVC: 2019 or later (2022 or above is recommended)
2. Monetdb for Hybrid Engine
- On windows, the required libraries and headers are already included in the repo.
- On Linux, see [Monetdb Easy Setup](https://www.monetdb.org/easy-setup/) for instructions.
- On MacOS, Monetdb can be easily installed in homebrew `brew install monetdb`.
3. Python 3.6 or above and install required packages in requirements.txt by `python3 -m pip install -r requirements.txt`
## Installation
AQuery is tested on mainstream operating systems such as Windows, macOS and Linux
### Windows
There're multiple options to run AQuery on Windows. You can use the native toolchain from Microsoft Visual Studio or gcc from Cygwin/MinGW or run it under Windows Subsystem for Linux.
- For WSL, Docker or Linux virtual machines, see Linux, Docker sections below
- For Visual Studio (Recommended):
1. Install python3.6 or above from [official website](https://www.python.org/downloads/windows/) or Microsoft Store.
2. Install Microsoft Visual Studio 2022 or later with **Desktop development with C++** selected.
3. Clone AQuery repo from [Github](https://github.com/sunyinqi0508/AQuery2)
4. Install python requirements with pip `python3 -m pip install -r requirements.txt`
5. Change the build_driver variable in aquery_config.py to "MSBuild"
6. The libraries and headers for Monetdb are already included in msc-plugins, however you can also choose to download them from [Monetdb Easy Setup](https://www.monetdb.org/easy-setup/) and put them in the same place.
- For Winlibs (Recommended):
- Download latest winlibs toolchain from the [official website](https://winlibs.com/)
- Since winlibs is linked with native windows runtime libraries (UCRT or MSVCRT), it offers better interoperatibility with other libraries built with MSVC such as python and monetdb.
- Other steps can be either the same as Visual Studio or Cygwin/Mingw (below) without ABI break.
- Copy or link `mingw64/libexec/gcc/<arch>/<version>/liblto-plugin.dll` to `mingw64/lib/bfd-plugins/` For Link time optimization support on gcc-ar and gcc-ranlib
- For CygWin/MinGW:
1. Install gcc and python3 using its **builtin package manager** instead of the one from python.org or windows store. (For Msys2, `pacman -S gcc python3`). Otherwise, ABI breakage may happen.
2. Clone AQuery repo from Github
3. Install python requirements
4. The prebuilt binaries are included in ./lib directory. However, you could also rebuild them from [source](https://github.com/MonetDB/MonetDB).
### macOS
- If you're using an arm-based mac (e.g. M1, M2 processors). Please go to the Application folder and right-click on the Terminal app, select 'Get Info' and ensure that the 'Open using Rosetta' option is unchecked. See the section below for more notes for arm-based macs.
- Install a package manager such as [homebrew](https://brew.sh)
- Install python3 and monetdb using homebrew `brew install python3 monetdb`
- Install C++ compiler come with Xcode commandline tool by `xcode-select --install` or from homebrew
- If you have multiple C++ compilers on the system. Specify C++ compiler by setting the **CXX** environment variable. e.g. `export CXX=clang`
- Install python packages from **requirements.txt**
**for arm64 macOS users**
- In theory, AQuery++ can work on both native arm64 and x86_64 through Rosetta. But for maximum performance, running native is preferred.
- However, they can't be mixed up, i.e. make sure every component, `python` , `C++ compiler`, `monetdb` library and system commandline utilities such as `uname` should have the same architecture.
- Use the script `./arch-check.sh` to check if relevant binaries all have the same architecture.
- In the case where binaries have different architectures, install the software with desired architecture and make an alias or link to ensure the newly installed binary is referred to.
- Because I can't get access to an arm-based mac to fully test this setup, there might still be issues. Please open an issue if you encounter any problems.
### Linux
- Install monetdb, see [Monetdb Easy Setup](https://www.monetdb.org/easy-setup/) for instructions.
- Install python3, C++ compiler and git. (For Ubuntu, run `apt update && apt install -y python3 python3-pip clang-14 libmonetdbe-dev git `)
- Install required python packages by `python3 -m pip install -r requirements.txt`
- If you have multiple C++ compilers on the system. Specify C++ compiler by setting the **CXX** environment variable. e.g. `export CXX=clang++-14`
- Note for anaconda users: the system libraries included in anaconda might differ from the ones your compiler is using. In this case, you might get errors similar to:
>ImportError: libstdc++.so.6: version `GLIBCXX_3.4.26' not found
In this case, upgrade anaconda or your compiler or use the python from your OS or package manager instead. Or (**NOT recommended**) copy/link the library from your system (e.g. /usr/lib/x86_64-linux-gnu/libstdc++.so.6) to anaconda's library directory (e.g. ~/Anaconda3/lib/).
### Docker:
- Alternatively, you can also use docker to run AQuery.
- Type `make docker` to build the docker image from scratch.
- For Arm-based Mac users, you would have to build and run the x86_64 docker image because MonetDB doesn't offer official binaries for arm64 Linux.
## Usage
`python3 prompt.py` will launch the interactive command prompt. The server binary will be automatically rebuilt and started.
#### Commands:
- `<sql statement>`: parse AQuery statement
- `f <filename>`: parse all AQuery statements in file
- `exec`: execute last parsed statement(s) with Hybrid Execution Engine. Hybrid Execution Engine decouples the query into two parts. The standard SQL (MonetDB dialect) part is executed by an Embedded version of Monetdb and everything else is executed by a post-process module which is generated by AQuery++ Compiler in C++ and then compiled and executed.
- `dbg` start debugging session
- `print`: printout parsed AQuery statements
- `save <OPTIONAL: filename>`: save current code snippet. will use random filename if not specified.
- `exit`: quit the prompt
- `r`: run the last generated code snippet
### Example:
`f moving_avg.a` <br>
`xexec`
See ./tests/ for more examples.
## Architecture ## Architecture
![Architecture](./docs/arch-hybrid.svg) ![Architecture](./docs/arch-hybrid.svg)
@ -40,53 +126,12 @@ AQuery++ Database is a cross-platform, In-Memory Column-Store Database that inco
## Known Issues: ## Known Issues:
- [x] User Module test
- [ ] Interval based triggers - [ ] Interval based triggers
- [x] Hot reloading server binary - [ ] Hot reloading server binary
- [x] Bug fixes: type deduction misaligned in Hybrid Engine - [x] Bug fixes: type deduction misaligned in Hybrid Engine
- [ ] Investigation: Using postproc only for q1 in Hybrid Engine (make is_special always on) - [ ] Investigation: Using postproc only for q1 in Hybrid Engine (make is_special always on)
- [x] Limitation: putting ColRefs back to monetdb. (Comparison)
- [ ] C++ Meta-Programming: Eliminate template recursions as much as possible. - [ ] C++ Meta-Programming: Eliminate template recursions as much as possible.
- [x] Limitation: Date and Time, String operations, Funcs in groupby agg.
- [ ] Functionality: Basic helper functions in aquery - [ ] Functionality: Basic helper functions in aquery
- [ ] Improvement: More DDLs, e.g. drop table, update table, etc. - [x] Improvement: More DDLs, e.g. drop table, update table, etc.
- [ ] Bug: Join-Aware Column management - [ ] Bug: Join-Aware Column management
- [ ] Bug: Order By after Group By - [ ] Bug: Order By after Group By
# Installation
## Requirements
1. Recent version of Linux, Windows or MacOS, with recent C++ compiler that has C++17 (1z) support. (however c++20 is recommended if available for heterogeneous lookup on unordered containers)
- GCC: 9.0 or above (g++ 7.x, 8.x fail to handle fold-expressions due to a compiler bug)
- Clang: 5.0 or above (Recommended)
- MSVC: 2017 or later (2022 or above is recommended)
2. Monetdb for Hybrid Engine
- On windows, the required libraries and headers are already included in the repo.
- On Linux, see [Monetdb Easy Setup](https://www.monetdb.org/easy-setup/) for instructions.
- On MacOS, Monetdb can be easily installed in homebrew `brew install monetdb`.
3. Python 3.6 or above and install required packages in requirements.txt by `python3 -m pip install -r requirements.txt`
## Usage
`python3 prompt.py` will launch the interactive command prompt. The server binary will be autometically rebuilt and started.
#### Commands:
- `<sql statement>`: parse AQuery statement
- `f <filename>`: parse all AQuery statements in file
- `dbg` start debugging session
- `print`: printout parsed AQuery statements
- `xexec`: execute last parsed statement(s) with Hybrid Execution Engine. Hybrid Execution Engine decouples the query into two parts. The standard SQL (MonetDB dialect) part is executed by an Embedded version of Monetdb and everything else is executed by a post-process module which is generated by AQuery++ Compiler in C++ and then compiled and executed.
- `save <OPTIONAL: filename>`: save current code snippet. will use random filename if not specified.
- `exit`: quit the prompt
- `exec`: execute last parsed statement(s) with AQuery Execution Engine (Old). AQuery Execution Engine executes query by compiling it to C++ code and then executing it.
- `r`: run the last generated code snippet
### Example:
`f moving_avg.a` <br>
`xexec`
See ./tests/ for more examples.
## Notes for arm64 macOS users
- In theory, AQuery++ could work on both native arm64 and x86_64 through Rosetta. But for maximum performance, running native is preferred.
- However, they can't be mixed up, i.e. make sure every component, `python` binary, `C++ compiler`, `monetdb` library and system commandline utilities such as `uname` should have the same architecture.
- Because I can't get access to an arm-based mac to fully test this setup, there might still be issues. Please open an issue if you encounter any problems.

@ -2,7 +2,7 @@
## GLOBAL CONFIGURATION FLAGS ## GLOBAL CONFIGURATION FLAGS
version_string = '0.4.5a' version_string = '0.4.7a'
add_path_to_ldpath = True add_path_to_ldpath = True
rebuild_backend = False rebuild_backend = False
run_backend = True run_backend = True
@ -13,7 +13,7 @@ os_platform = 'unknown'
build_driver = 'Makefile' build_driver = 'Makefile'
def init_config(): def init_config():
global __config_initialized__, os_platform, msbuildroot global __config_initialized__, os_platform, msbuildroot, build_driver
## SETUP ENVIRONMENT VARIABLES ## SETUP ENVIRONMENT VARIABLES
# __config_initialized__ = False # __config_initialized__ = False
#os_platform = 'unkown' #os_platform = 'unkown'
@ -44,15 +44,23 @@ def init_config():
if os_platform == 'win': if os_platform == 'win':
add_dll_dir(cygroot) add_dll_dir(cygroot)
add_dll_dir(os.path.abspath('./msc-plugin')) add_dll_dir(os.path.abspath('./msc-plugin'))
import vswhere if build_driver == 'Auto':
vsloc = vswhere.find(prerelease = True, latest = True, prop = 'installationPath') try:
if vsloc: import vswhere
msbuildroot = vsloc[0] + '/MSBuild/Current/Bin/MSBuild.exe' vsloc = vswhere.find(prerelease = True, latest = True, prop = 'installationPath')
else: if vsloc:
print('Warning: No Visual Studio installation found.') msbuildroot = vsloc[0] + '/MSBuild/Current/Bin/MSBuild.exe'
build_driver = 'MSBuild'
else:
print('Warning: No Visual Studio installation found.')
build_driver = 'Makefile'
except ModuleNotFoundError:
build_driver = 'Makefile'
# print("adding path") # print("adding path")
else: else:
import readline import readline
if build_driver == 'Auto':
build_driver = 'Makefile'
if os_platform == 'cygwin': if os_platform == 'cygwin':
add_dll_dir('./lib') add_dll_dir('./lib')
__config_initialized__ = True __config_initialized__ = True

@ -0,0 +1,21 @@
ARCH=`uname -m`
ARCH2=`arch`
echo Current architechure: $ARCH $ARCH2
echo Current shell: $SHELL
PASSED=1
for i in python3 c++ make ranlib libtool $SHELL
do
FILEPATH=`which $i`
FILEINFO=`file $FILEPATH`
if [[ $FILEINFO =~ $ARCH ]]; then
echo $i@$FILEPATH: passed
else
echo "\033[1;31mERROR\033[0m: Architecture of $i is not $ARCH: $FILEINFO"
PASSED=0
fi
done
if [[ PASSED -eq 1 ]]; then
echo "\033[1;32mBinary archtechure check passed\033[0m"
fi

@ -14,16 +14,17 @@ class checksums:
libaquery_a : Optional[Union[bytes, bool]] = None libaquery_a : Optional[Union[bytes, bool]] = None
pch_hpp_gch : Optional[Union[bytes, bool]] = None pch_hpp_gch : Optional[Union[bytes, bool]] = None
server : Optional[Union[bytes, bool]] = None server : Optional[Union[bytes, bool]] = None
sources : Union[Dict[str, bytes], bool] = None sources : Optional[Union[Dict[str, bytes], bool]] = None
env : str = '' env : str = ''
def calc(self, libaquery_a = 'libaquery.a' , def calc(self, compiler_name, libaquery_a = 'libaquery.a' ,
pch_hpp_gch = 'server/pch.hpp.gch', pch_hpp_gch = 'server/pch.hpp.gch',
server = 'server.so' server = 'server.so'
): ):
from platform import machine from platform import machine
self.env = (aquery_config.os_platform + self.env = (aquery_config.os_platform +
machine() + machine() +
aquery_config.build_driver aquery_config.build_driver +
compiler_name
) )
for key in self.__dict__.keys(): for key in self.__dict__.keys():
try: try:
@ -69,7 +70,7 @@ class checksums:
class build_manager: class build_manager:
sourcefiles = [ sourcefiles = [
'build.py', 'build.py', 'Makefile',
'server/server.cpp', 'server/io.cpp', 'server/server.cpp', 'server/io.cpp',
'server/monetdb_conn.cpp', 'server/threading.cpp', 'server/monetdb_conn.cpp', 'server/threading.cpp',
'server/winhelper.cpp' 'server/winhelper.cpp'
@ -93,8 +94,8 @@ class build_manager:
ret = True ret = True
for c in self.build_cmd: for c in self.build_cmd:
if c: if c:
try: try: # only last success matters
ret = subprocess.call(c, stdout = stdout, stderr = stderr) and ret ret = not subprocess.call(c, stdout = stdout, stderr = stderr) # and ret
except (FileNotFoundError): except (FileNotFoundError):
ret = False ret = False
pass pass
@ -104,7 +105,10 @@ class build_manager:
def __init__(self, mgr : 'build_manager') -> None: def __init__(self, mgr : 'build_manager') -> None:
super().__init__(mgr) super().__init__(mgr)
os.environ['PCH'] = f'{mgr.PCH}' os.environ['PCH'] = f'{mgr.PCH}'
os.environ['CXX'] = mgr.cxx if mgr.cxx else 'c++' if 'CXX' not in os.environ:
os.environ['CXX'] = mgr.cxx if mgr.cxx else 'c++'
else:
mgr.cxx = os.environ['CXX']
def libaquery_a(self): def libaquery_a(self):
self.build_cmd = [['rm', 'libaquery.a'],['make', 'libaquery.a']] self.build_cmd = [['rm', 'libaquery.a'],['make', 'libaquery.a']]
@ -129,6 +133,10 @@ class build_manager:
class MSBuildDriver(DriverBase): class MSBuildDriver(DriverBase):
platform_map = {'amd64':'x64', 'arm64':'arm64', 'x86':'win32'} platform_map = {'amd64':'x64', 'arm64':'arm64', 'x86':'win32'}
opt_map = {'0':'Debug', '1':'RelWithDebugInfo', '2':'Release', '3':'Release', '4':'Release'} opt_map = {'0':'Debug', '1':'RelWithDebugInfo', '2':'Release', '3':'Release', '4':'Release'}
def __init__(self, mgr : 'build_manager') -> None:
super().__init__(mgr)
mgr.cxx = aquery_config.msbuildroot
def get_flags(self): def get_flags(self):
self.platform = self.platform_map[self.mgr.Platform] self.platform = self.platform_map[self.mgr.Platform]
self.platform = f'/p:platform={self.platform}' self.platform = f'/p:platform={self.platform}'
@ -142,7 +150,7 @@ class build_manager:
return self.build() return self.build()
def pch(self): def pch(self):
pass return True
def server(self): def server(self):
loc = os.path.abspath('./msc-plugin/server.vcxproj') loc = os.path.abspath('./msc-plugin/server.vcxproj')
@ -184,7 +192,7 @@ class build_manager:
libaquery_a = 'libaquery.a' libaquery_a = 'libaquery.a'
if aquery_config.os_platform == 'win': if aquery_config.os_platform == 'win':
libaquery_a = 'libaquery.lib' libaquery_a = 'libaquery.lib'
current.calc(libaquery_a) current.calc(self.cxx, libaquery_a)
try: try:
with open('.cached', 'rb') as cache_sig: with open('.cached', 'rb') as cache_sig:
cached = pickle.loads(cache_sig.read()) cached = pickle.loads(cache_sig.read())
@ -193,22 +201,27 @@ class build_manager:
self.cache_status = current != cached self.cache_status = current != cached
success = True success = True
if force or self.cache_status.sources: if (force or
self.driver.pch() self.cache_status.sources or
self.driver.libaquery_a() self.cache_status.env
self.driver.server() ):
success &= self.driver.pch()
success &= self.driver.libaquery_a()
success &= self.driver.server()
else: else:
if self.cache_status.libaquery_a: if self.cache_status.libaquery_a:
success = self.driver.libaquery_a() and success success &= self.driver.libaquery_a()
if self.cache_status.pch_hpp_gch: if self.cache_status.pch_hpp_gch:
success = self.driver.pch() and success success &= self.driver.pch()
if self.cache_status.server: if self.cache_status.server:
success = self.driver.server() and success success &= self.driver.server()
if success: if success:
current.calc(libaquery_a) current.calc(self.cxx, libaquery_a)
with open('.cached', 'wb') as cache_sig: with open('.cached', 'wb') as cache_sig:
cache_sig.write(pickle.dumps(current)) cache_sig.write(pickle.dumps(current))
else: else:
if aquery_config.os_platform == 'mac':
os.system('./arch-check.sh')
try: try:
os.remove('./.cached') os.remove('./.cached')
except: except:

@ -106,11 +106,13 @@ ULongT = Types(8, name = 'uint64', sqlname = 'UINT64', fp_type=DoubleT)
UIntT = Types(7, name = 'uint32', sqlname = 'UINT32', long_type=ULongT, fp_type=FloatT) UIntT = Types(7, name = 'uint32', sqlname = 'UINT32', long_type=ULongT, fp_type=FloatT)
UShortT = Types(6, name = 'uint16', sqlname = 'UINT16', long_type=ULongT, fp_type=FloatT) UShortT = Types(6, name = 'uint16', sqlname = 'UINT16', long_type=ULongT, fp_type=FloatT)
UByteT = Types(5, name = 'uint8', sqlname = 'UINT8', long_type=ULongT, fp_type=FloatT) UByteT = Types(5, name = 'uint8', sqlname = 'UINT8', long_type=ULongT, fp_type=FloatT)
StrT = Types(200, name = 'str', cname = 'const char*', sqlname='VARCHAR', ctype_name = 'types::ASTR') StrT = Types(200, name = 'str', cname = 'const char*', sqlname='TEXT', ctype_name = 'types::ASTR')
TextT = Types(200, name = 'text', cname = 'const char*', sqlname='TEXT', ctype_name = 'types::ASTR')
VarcharT = Types(200, name = 'varchar', cname = 'const char*', sqlname='VARCHAR', ctype_name = 'types::ASTR')
VoidT = Types(200, name = 'void', cname = 'void', sqlname='Null', ctype_name = 'types::None') VoidT = Types(200, name = 'void', cname = 'void', sqlname='Null', ctype_name = 'types::None')
class VectorT(Types): class VectorT(Types):
def __init__(self, inner_type : Types, vector_type:str = 'ColRef'): def __init__(self, inner_type : Types, vector_type:str = 'vector_type'):
self.inner_type = inner_type self.inner_type = inner_type
self.vector_type = vector_type self.vector_type = vector_type
@ -119,7 +121,7 @@ class VectorT(Types):
return f'{self.vector_type}<{self.inner_type.name}>' return f'{self.vector_type}<{self.inner_type.name}>'
@property @property
def sqlname(self) -> str: def sqlname(self) -> str:
return 'BINARY' return 'BIGINT'
@property @property
def cname(self) -> str: def cname(self) -> str:
return self.name return self.name
@ -138,7 +140,10 @@ int_types : Dict[str, Types] = _ty_make_dict('t.sqlname.lower()', LongT, ByteT,
uint_types : Dict[str, Types] = _ty_make_dict('t.sqlname.lower()', ULongT, UByteT, UShortT, UIntT) uint_types : Dict[str, Types] = _ty_make_dict('t.sqlname.lower()', ULongT, UByteT, UShortT, UIntT)
fp_types : Dict[str, Types] = _ty_make_dict('t.sqlname.lower()', FloatT, DoubleT) fp_types : Dict[str, Types] = _ty_make_dict('t.sqlname.lower()', FloatT, DoubleT)
temporal_types : Dict[str, Types] = _ty_make_dict('t.sqlname.lower()', DateT, TimeT, TimeStampT) temporal_types : Dict[str, Types] = _ty_make_dict('t.sqlname.lower()', DateT, TimeT, TimeStampT)
builtin_types : Dict[str, Types] = {**_ty_make_dict('t.sqlname.lower()', AnyT, StrT), **int_types, **fp_types, **temporal_types} builtin_types : Dict[str, Types] = {
'string' : StrT,
**_ty_make_dict('t.sqlname.lower()', AnyT, TextT, VarcharT),
**int_types, **fp_types, **temporal_types}
def get_int128_support(): def get_int128_support():
for t in int_types.values(): for t in int_types.values():
@ -267,7 +272,9 @@ def windowed_fn_behavor(op: OperatorBase, c_code, *x):
# arithmetic # arithmetic
opadd = OperatorBase('add', 2, auto_extension, cname = '+', sqlname = '+', call = binary_op_behavior) opadd = OperatorBase('add', 2, auto_extension, cname = '+', sqlname = '+', call = binary_op_behavior)
opdiv = OperatorBase('div', 2, fp(auto_extension), cname = '/', sqlname = '/', call = binary_op_behavior) # monetdb wont extend int division to fp type
# opdiv = OperatorBase('div', 2, fp(auto_extension), cname = '/', sqlname = '/', call = binary_op_behavior)
opdiv = OperatorBase('div', 2, auto_extension, cname = '/', sqlname = '/', call = binary_op_behavior)
opmul = OperatorBase('mul', 2, fp(auto_extension), cname = '*', sqlname = '*', call = binary_op_behavior) opmul = OperatorBase('mul', 2, fp(auto_extension), cname = '*', sqlname = '*', call = binary_op_behavior)
opsub = OperatorBase('sub', 2, auto_extension, cname = '-', sqlname = '-', call = binary_op_behavior) opsub = OperatorBase('sub', 2, auto_extension, cname = '-', sqlname = '-', call = binary_op_behavior)
opmod = OperatorBase('mod', 2, auto_extension_int, cname = '%', sqlname = '%', call = binary_op_behavior) opmod = OperatorBase('mod', 2, auto_extension_int, cname = '%', sqlname = '%', call = binary_op_behavior)
@ -288,7 +295,9 @@ opdistinct = OperatorBase('distinct', 1, as_is, cname = '.distinct()', sqlname =
fnmax = OperatorBase('max', 1, as_is, cname = 'max', sqlname = 'MAX', call = fn_behavior) fnmax = OperatorBase('max', 1, as_is, cname = 'max', sqlname = 'MAX', call = fn_behavior)
fnmin = OperatorBase('min', 1, as_is, cname = 'min', sqlname = 'MIN', call = fn_behavior) fnmin = OperatorBase('min', 1, as_is, cname = 'min', sqlname = 'MIN', call = fn_behavior)
fndeltas = OperatorBase('deltas', 1, as_is, cname = 'deltas', sqlname = 'DELTAS', call = fn_behavior) fndeltas = OperatorBase('deltas', 1, as_is, cname = 'deltas', sqlname = 'DELTAS', call = fn_behavior)
fnratios = OperatorBase('ratios', [1, 2], fp(ty_clamp(as_is, -1)), cname = 'ratios', sqlname = 'RATIOS', call = windowed_fn_behavor)
fnlast = OperatorBase('last', 1, as_is, cname = 'last', sqlname = 'LAST', call = fn_behavior) fnlast = OperatorBase('last', 1, as_is, cname = 'last', sqlname = 'LAST', call = fn_behavior)
fnfirst = OperatorBase('first', 1, as_is, cname = 'frist', sqlname = 'FRIST', call = fn_behavior)
#fnsum = OperatorBase('sum', 1, ext(auto_extension), cname = 'sum', sqlname = 'SUM', call = fn_behavior) #fnsum = OperatorBase('sum', 1, ext(auto_extension), cname = 'sum', sqlname = 'SUM', call = fn_behavior)
#fnavg = OperatorBase('avg', 1, fp(ext(auto_extension)), cname = 'avg', sqlname = 'AVG', call = fn_behavior) #fnavg = OperatorBase('avg', 1, fp(ext(auto_extension)), cname = 'avg', sqlname = 'AVG', call = fn_behavior)
fnsum = OperatorBase('sum', 1, long_return, cname = 'sum', sqlname = 'SUM', call = fn_behavior) fnsum = OperatorBase('sum', 1, long_return, cname = 'sum', sqlname = 'SUM', call = fn_behavior)
@ -324,7 +333,7 @@ builtin_unary_logical = _op_make_dict(opnot)
builtin_unary_arith = _op_make_dict(opneg) builtin_unary_arith = _op_make_dict(opneg)
builtin_unary_special = _op_make_dict(spnull, opdistinct) builtin_unary_special = _op_make_dict(spnull, opdistinct)
builtin_cstdlib = _op_make_dict(fnsqrt, fnlog, fnsin, fncos, fntan, fnpow) builtin_cstdlib = _op_make_dict(fnsqrt, fnlog, fnsin, fncos, fntan, fnpow)
builtin_func = _op_make_dict(fnmax, fnmin, fnsum, fnavg, fnmaxs, fnmins, fndeltas, fnlast, fnsums, fnavgs, fncnt) builtin_func = _op_make_dict(fnmax, fnmin, fnsum, fnavg, fnmaxs, fnmins, fndeltas, fnratios, fnlast, fnfirst, fnsums, fnavgs, fncnt)
user_module_func = {} user_module_func = {}
builtin_operators : Dict[str, OperatorBase] = {**builtin_binary_arith, **builtin_binary_logical, builtin_operators : Dict[str, OperatorBase] = {**builtin_binary_arith, **builtin_binary_logical,
**builtin_unary_arith, **builtin_unary_logical, **builtin_unary_special, **builtin_func, **builtin_cstdlib, **builtin_unary_arith, **builtin_unary_logical, **builtin_unary_special, **builtin_func, **builtin_cstdlib,

@ -137,3 +137,10 @@ def add_dll_dir(dll: str):
os.environ['PATH'] = os.path.abspath(dll) + os.pathsep + os.environ['PATH'] os.environ['PATH'] = os.path.abspath(dll) + os.pathsep + os.environ['PATH']
nullstream = open(os.devnull, 'w') nullstream = open(os.devnull, 'w')
def clamp(val, minval, maxval):
return min(max(val, minval), maxval)
def escape_qoutes(string : str):
return re.sub(r'^\'', r'\'',re.sub(r'([^\\])\'', r'\1\'', string))

@ -435,7 +435,7 @@ gmtime_r(const time_t *__restrict__ timep, struct tm *__restrict__ result)
#define HAVE_SOCKLEN_T 1 #define HAVE_SOCKLEN_T 1
#ifndef _MSC_VER #ifndef _MSC_VER
#define SOCKET int // #define SOCKET int
#define closesocket close #define closesocket close
#endif #endif

@ -29,7 +29,7 @@ prompt_help = '''\
******** AQuery Prompt Help ********* ******** AQuery Prompt Help *********
help: help:
print out this message print this help message
help commandline: help commandline:
print help message for AQuery Commandline print help message for AQuery Commandline
<sql statement>: <sql statement>:
@ -43,7 +43,7 @@ dbg:
print: print:
printout parsed sql statements printout parsed sql statements
exec: exec:
execute last parsed statement(s) with AQuery Execution Engine execute last parsed statement(s) with AQuery Execution Engine (disabled)
xexec: xexec:
execute last parsed statement(s) with Hybrid Execution Engine execute last parsed statement(s) with Hybrid Execution Engine
r: r:
@ -336,7 +336,7 @@ def prompt(running = lambda:True, next = lambda:input('> '), state = None):
time.sleep(.00001) time.sleep(.00001)
og_q : str = next() og_q : str = next()
q = og_q.lower().strip() q = og_q.lower().strip()
if q == 'exec': # generate build and run (AQuery Engine) if False and q == 'exec': # generate build and run (AQuery Engine)
state.cfg.backend_type = Backend_Type.BACKEND_AQuery.value state.cfg.backend_type = Backend_Type.BACKEND_AQuery.value
cxt = engine.exec(state.stmts, cxt, keep) cxt = engine.exec(state.stmts, cxt, keep)
if state.buildmgr.build_dll() == 0: if state.buildmgr.build_dll() == 0:
@ -352,7 +352,7 @@ def prompt(running = lambda:True, next = lambda:input('> '), state = None):
else: else:
print(prompt_help) print(prompt_help)
continue continue
elif q.startswith('xexec'): # generate build and run (MonetDB Engine) elif q.startswith('xexec') or q.startswith('exec'): # generate build and run (MonetDB Engine)
state.cfg.backend_type = Backend_Type.BACKEND_MonetDB.value state.cfg.backend_type = Backend_Type.BACKEND_MonetDB.value
cxt = xengine.exec(state.stmts, cxt, keep) cxt = xengine.exec(state.stmts, cxt, keep)
@ -420,7 +420,7 @@ def prompt(running = lambda:True, next = lambda:input('> '), state = None):
continue continue
elif q == 'format' or q == 'fmt': elif q == 'format' or q == 'fmt':
subprocess.call(['clang-format', 'out.cpp']) subprocess.call(['clang-format', 'out.cpp'])
elif q == 'exit': elif q == 'exit' or q == 'exit()':
rm(state) rm(state)
exit() exit()
elif q == 'r': # build and run elif q == 'r': # build and run

@ -18,6 +18,8 @@ def generate(ast, cxt):
ast_node.types[k](None, ast, cxt) ast_node.types[k](None, ast, cxt)
def exec(stmts, cxt = None, keep = False): def exec(stmts, cxt = None, keep = False):
if 'stmts' not in stmts:
return
cxt = initialize(cxt, keep) cxt = initialize(cxt, keep)
stmts_stmts = stmts['stmts'] stmts_stmts = stmts['stmts']
if type(stmts_stmts) is list: if type(stmts_stmts) is list:

@ -2,6 +2,7 @@ from copy import deepcopy
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum, auto from enum import Enum, auto
from typing import Set, Tuple, Dict, Union, List, Optional from typing import Set, Tuple, Dict, Union, List, Optional
from engine.types import * from engine.types import *
from engine.utils import enlist, base62uuid, base62alp, get_legal_name from engine.utils import enlist, base62uuid, base62alp, get_legal_name
from reconstruct.storage import Context, TableInfo, ColRef from reconstruct.storage import Context, TableInfo, ColRef
@ -133,7 +134,7 @@ class projection(ast_node):
sql_expr = expr(self, e, c_code=False) sql_expr = expr(self, e, c_code=False)
this_type = proj_expr.type this_type = proj_expr.type
name = proj_expr.sql name = proj_expr.sql
compound = True # compound column compound = [proj_expr.is_compound > 1] # compound column
proj_expr.cols_mentioned = self.datasource.rec proj_expr.cols_mentioned = self.datasource.rec
alias = '' alias = ''
if 'name' in proj: # renaming column by AS keyword if 'name' in proj: # renaming column by AS keyword
@ -142,23 +143,29 @@ class projection(ast_node):
if not proj_expr.is_special: if not proj_expr.is_special:
if proj_expr.node == '*': if proj_expr.node == '*':
name = [c.get_full_name() for c in self.datasource.rec] name = [c.get_full_name() for c in self.datasource.rec]
this_type = [c.type for c in self.datasource.rec]
compound = [c.compound for c in self.datasource.rec]
proj_expr = [expr(self, c.name) for c in self.datasource.rec]
else: else:
y = lambda x:x y = lambda x:x
count = lambda : 'count(*)' count = lambda : 'count(*)'
name = enlist(sql_expr.eval(False, y, count=count)) name = enlist(sql_expr.eval(False, y, count=count))
for n in name: this_type = enlist(this_type)
proj_expr = enlist(proj_expr)
for t, n, pexpr, cp in zip(this_type, name, proj_expr, compound):
t = VectorT(t) if cp else t
offset = len(col_exprs) offset = len(col_exprs)
if n not in self.var_table: if n not in self.var_table:
self.var_table[n] = offset self.var_table[n] = offset
if proj_expr.is_ColExpr and type(proj_expr.raw_col) is ColRef: if pexpr.is_ColExpr and type(pexpr.raw_col) is ColRef:
for _alias in (proj_expr.raw_col.table.alias): for _alias in (pexpr.raw_col.table.alias):
self.var_table[f'{_alias}.'+n] = offset self.var_table[f'{_alias}.'+n] = offset
proj_map[i] = [this_type, offset, proj_expr] proj_map[i] = [t, offset, pexpr]
col_expr = n + ' AS ' + alias if alias else n col_expr = n + ' AS ' + alias if alias else n
if alias: if alias:
self.var_table[alias] = offset self.var_table[alias] = offset
col_exprs.append((col_expr, proj_expr.type)) col_exprs.append((col_expr, t))
i += 1 i += 1
else: else:
self.context.headers.add('"./server/aggregations.h"') self.context.headers.add('"./server/aggregations.h"')
@ -169,7 +176,8 @@ class projection(ast_node):
i += 1 i += 1
name = enlist(name) name = enlist(name)
disp_name = [get_legal_name(alias if alias else n) for n in name] disp_name = [get_legal_name(alias if alias else n) for n in name]
this_type = enlist(this_type)
elif type(proj) is str: elif type(proj) is str:
col = self.datasource.get_col(proj) col = self.datasource.get_col(proj)
this_type = col.type this_type = col.type
@ -178,8 +186,8 @@ class projection(ast_node):
# name = col.name # name = col.name
self.datasource.rec = None self.datasource.rec = None
# TODO: Type deduction in Python # TODO: Type deduction in Python
for n in disp_name: for t, n, c in zip(this_type, disp_name, compound):
cols.append(ColRef(this_type, self.out_table, None, n, len(cols), compound=compound)) cols.append(ColRef(t, self.out_table, None, n, len(cols), compound=c))
self.out_table.add_cols(cols, new = False) self.out_table.add_cols(cols, new = False)
@ -213,7 +221,7 @@ class projection(ast_node):
self.add(self.group_node.sql) self.add(self.group_node.sql)
if self.col_ext or self.group_node and self.group_node.use_sp_gb: if self.col_ext or self.group_node and self.group_node.use_sp_gb:
self.use_postproc = True self.has_postproc = True
o = self.assumptions o = self.assumptions
if 'orderby' in node: if 'orderby' in node:
@ -223,7 +231,7 @@ class projection(ast_node):
if 'outfile' in node: if 'outfile' in node:
self.outfile = outfile(self, node['outfile'], sql = self.sql) self.outfile = outfile(self, node['outfile'], sql = self.sql)
if not self.use_postproc: if not self.has_postproc:
self.sql += self.outfile.sql self.sql += self.outfile.sql
else: else:
self.outfile = None self.outfile = None
@ -280,10 +288,11 @@ class projection(ast_node):
self.datasource.all_cols().difference(self.group_node.refs)) self.datasource.all_cols().difference(self.group_node.refs))
) and val[2].is_compound # compound val not in key ) and val[2].is_compound # compound val not in key
# or # or
# val[2].is_compound > 1
# (not self.group_node and val[2].is_compound) # (not self.group_node and val[2].is_compound)
): ):
out_typenames[key] = f'ColRef<{out_typenames[key]}>' out_typenames[key] = f'vector_type<{out_typenames[key]}>'
self.out_table.columns[key].compound = True
outtable_col_nameslist = ', '.join([f'"{c.name}"' for c in self.out_table.columns]) outtable_col_nameslist = ', '.join([f'"{c.name}"' for c in self.out_table.columns])
self.outtable_col_names = 'names_' + base62uuid(4) self.outtable_col_names = 'names_' + base62uuid(4)
self.context.emitc(f'const char* {self.outtable_col_names}[] = {{{outtable_col_nameslist}}};') self.context.emitc(f'const char* {self.outtable_col_names}[] = {{{outtable_col_nameslist}}};')
@ -523,7 +532,7 @@ class groupby_c(ast_node):
materialize_builtin['_builtin_len'] = len_var materialize_builtin['_builtin_len'] = len_var
if '_builtin_ret' in ex.udf_called.builtin_used: if '_builtin_ret' in ex.udf_called.builtin_used:
define_len_var() define_len_var()
gscanner.add(f'{ce[0]}.emplace_back({{{len_var}}});\n') gscanner.add(f'{ce[0]}.emplace_back({len_var});\n')
materialize_builtin['_builtin_ret'] = f'{ce[0]}.back()' materialize_builtin['_builtin_ret'] = f'{ce[0]}.back()'
gscanner.add(f'{ex.eval(c_code = True, y=get_var_names, materialize_builtin = materialize_builtin)};\n') gscanner.add(f'{ex.eval(c_code = True, y=get_var_names, materialize_builtin = materialize_builtin)};\n')
continue continue
@ -608,6 +617,7 @@ class join(ast_node):
self.join_conditions = [] self.join_conditions = []
# self.tmp_name = 'join_' + base62uuid(4) # self.tmp_name = 'join_' + base62uuid(4)
# self.datasource = TableInfo(self.tmp_name, [], self.context) # self.datasource = TableInfo(self.tmp_name, [], self.context)
def append(self, tbls, __alias = ''): def append(self, tbls, __alias = ''):
alias = lambda t : t + ' ' + __alias if len(__alias) else t alias = lambda t : t + ' ' + __alias if len(__alias) else t
if type(tbls) is join: if type(tbls) is join:
@ -652,8 +662,11 @@ class join(ast_node):
self.have_sep = True self.have_sep = True
j = join(self, node[keys[0]]) j = join(self, node[keys[0]])
tablename = f' {keys[0]} {j}' tablename = f' {keys[0]} {j}'
if len(keys) > 1 and keys[1].lower() == 'on': if len(keys) > 1 :
tablename += f' on {expr(self, node[keys[1]])}' if keys[1].lower() == 'on':
tablename += f' ON {expr(self, node[keys[1]])}'
elif keys[1].lower() == 'using':
tablename += f' USING {expr(self, node[keys[1]])}'
self.joins.append((tablename, self.have_sep)) self.joins.append((tablename, self.have_sep))
self.tables += j.tables self.tables += j.tables
self.tables_dir = {**self.tables_dir, **j.tables_dir} self.tables_dir = {**self.tables_dir, **j.tables_dir}
@ -722,13 +735,25 @@ class join(ast_node):
class filter(ast_node): class filter(ast_node):
name = 'where' name = 'where'
def produce(self, node): def produce(self, node):
self.add(expr(self, node).sql) filter_expr = expr(self, node)
self.add(filter_expr.sql)
self.datasource.join_conditions += filter_expr.join_conditions
class create_table(ast_node): class create_table(ast_node):
name = 'create_table' name = 'create_table'
first_order = name first_order = name
def init(self, node): def init(self, node):
node = node[self.name]
if 'query' in node:
if 'name' not in node:
raise ValueError("Table name not specified")
projection_node = node['query']
projection_node['into'] = node['name']
projection(None, projection_node, self.context)
self.produce = lambda *_: None
self.spawn = lambda *_: None
self.consume = lambda *_: None
return
if self.parent is None: if self.parent is None:
self.context.sql_begin() self.context.sql_begin()
self.sql = 'CREATE TABLE ' self.sql = 'CREATE TABLE '
@ -745,16 +770,45 @@ class create_table(ast_node):
if self.context.use_columnstore: if self.context.use_columnstore:
self.sql += ' engine=ColumnStore' self.sql += ' engine=ColumnStore'
class drop(ast_node):
name = 'drop'
first_order = name
def produce(self, node):
node = node['drop']
tbl_name = node['table']
if tbl_name in self.context.tables_byname:
tbl_obj = self.context.tables_byname[tbl_name]
# TODO: delete in postproc engine
self.context.tables_byname.pop(tbl_name)
self.context.tables.remove(tbl_obj)
self.sql += 'TABLE IF EXISTS ' + tbl_name
return
elif 'if_exists' not in node or not node['if_exists']:
print(f'Error: table {tbl_name} not found.')
self.sql = ''
class insert(ast_node): class insert(ast_node):
name = 'insert' name = 'insert'
first_order = name first_order = name
def init(self, node):
values = node['query']
complex_query_kw = ['from', 'where', 'groupby', 'having', 'orderby', 'limit']
if any([kw in values for kw in complex_query_kw]):
values['into'] = node['insert']
projection(None, values, self.context)
self.produce = lambda*_:None
self.spawn = lambda*_:None
self.consume = lambda*_:None
else:
super().init(node)
def produce(self, node): def produce(self, node):
values = node['query']['select'] values = node['query']['select']
tbl = node['insert'] tbl = node['insert']
self.sql = f'INSERT INTO {tbl} VALUES(' self.sql = f'INSERT INTO {tbl} VALUES('
# if len(values) != table.n_cols: # if len(values) != table.n_cols:
# raise ValueError("Column Mismatch") # raise ValueError("Column Mismatch")
list_values = [] list_values = []
for i, s in enumerate(values): for i, s in enumerate(values):
if 'value' in s: if 'value' in s:
@ -851,7 +905,7 @@ class outfile(ast_node):
def init(self, _): def init(self, _):
assert(isinstance(self.parent, projection)) assert(isinstance(self.parent, projection))
if not self.parent.use_postproc: if not self.parent.has_postproc:
if self.context.dialect == 'MonetDB': if self.context.dialect == 'MonetDB':
self.produce = self.produce_monetdb self.produce = self.produce_monetdb
else: else:

@ -12,6 +12,11 @@ from engine.types import *
class expr(ast_node): class expr(ast_node):
name='expr' name='expr'
valid_joincond = {
0 : ('and', 'eq', 'not'),
1 : ('or', 'neq', 'not'),
2 : ('', '', '')
}
@property @property
def udf_decltypecall(self): def udf_decltypecall(self):
return self._udf_decltypecall if self._udf_decltypecall else self.sql return self._udf_decltypecall if self._udf_decltypecall else self.sql
@ -46,6 +51,7 @@ class expr(ast_node):
self.node = node self.node = node
self.supress_undefined = supress_undefined self.supress_undefined = supress_undefined
if(type(parent) is expr): if(type(parent) is expr):
self.next_valid = parent.next_valid
self.inside_agg = parent.inside_agg self.inside_agg = parent.inside_agg
self.is_udfexpr = parent.is_udfexpr self.is_udfexpr = parent.is_udfexpr
self.is_agg_func = parent.is_agg_func self.is_agg_func = parent.is_agg_func
@ -53,6 +59,8 @@ class expr(ast_node):
self.c_code = parent.c_code self.c_code = parent.c_code
self.builtin_vars = parent.builtin_vars self.builtin_vars = parent.builtin_vars
else: else:
self.join_conditions = []
self.next_valid = 0
self.is_agg_func = False self.is_agg_func = False
self.is_udfexpr = type(parent) is udf self.is_udfexpr = type(parent) is udf
self.root : expr = self self.root : expr = self
@ -80,7 +88,7 @@ class expr(ast_node):
self.udf_map = parent.context.udf_map self.udf_map = parent.context.udf_map
self.func_maps = {**builtin_func, **self.udf_map, **user_module_func} self.func_maps = {**builtin_func, **self.udf_map, **user_module_func}
self.operators = {**builtin_operators, **self.udf_map, **user_module_func} self.operators = {**builtin_operators, **self.udf_map, **user_module_func}
self.ext_aggfuncs = ['sum', 'avg', 'count', 'min', 'max', 'last'] self.ext_aggfuncs = ['sum', 'avg', 'count', 'min', 'max', 'last', 'first']
def produce(self, node): def produce(self, node):
from engine.utils import enlist from engine.utils import enlist
@ -92,9 +100,18 @@ class expr(ast_node):
else: else:
if len(node) > 1: if len(node) > 1:
print(f'Parser Error: {node} has more than 1 dict entry.') print(f'Parser Error: {node} has more than 1 dict entry.')
is_joincond = False
for key, val in node.items(): for key, val in node.items():
key = key.lower() key = key.lower()
if key not in self.valid_joincond[self.next_valid]:
self.next_valid = 2
else:
if key == self.valid_joincond[self.next_valid][2]:
self.next_valid = not self.next_valid
elif key == self.valid_joincond[self.next_valid][1]:
self.next_valid = 2
is_joincond = True
if key in self.operators: if key in self.operators:
if key in builtin_func: if key in builtin_func:
if self.is_agg_func: if self.is_agg_func:
@ -114,9 +131,9 @@ class expr(ast_node):
str_vals = [e.sql for e in exp_vals] str_vals = [e.sql for e in exp_vals]
type_vals = [e.type for e in exp_vals] type_vals = [e.type for e in exp_vals]
is_compound = any([e.is_compound for e in exp_vals]) is_compound = max([e.is_compound for e in exp_vals])
if key in self.ext_aggfuncs: if key in self.ext_aggfuncs:
self.is_compound = False self.is_compound = max(0, is_compound - 1)
else: else:
self.is_compound = is_compound self.is_compound = is_compound
try: try:
@ -134,7 +151,7 @@ class expr(ast_node):
self.sql = op(self.c_code, *str_vals) self.sql = op(self.c_code, *str_vals)
special_func = [*self.context.udf_map.keys(), *self.context.module_map.keys(), special_func = [*self.context.udf_map.keys(), *self.context.module_map.keys(),
"maxs", "mins", "avgs", "sums", "deltas", "last"] "maxs", "mins", "avgs", "sums", "deltas", "last", "first", "ratios"]
if self.context.special_gb: if self.context.special_gb:
special_func = [*special_func, *self.ext_aggfuncs] special_func = [*special_func, *self.ext_aggfuncs]
@ -200,6 +217,9 @@ class expr(ast_node):
else: else:
print(f'Undefined expr: {key}{val}') print(f'Undefined expr: {key}{val}')
if (is_joincond and len(self.children) == 2
and all([c.is_ColExpr for c in self.children])) :
self.root.join_conditions.append((c.raw_col for c in self.children))
if type(node) is str: if type(node) is str:
if self.is_udfexpr: if self.is_udfexpr:
@ -259,6 +279,7 @@ class expr(ast_node):
self.sql = table_name + self.raw_col.name self.sql = table_name + self.raw_col.name
self.type = self.raw_col.type self.type = self.raw_col.type
self.is_compound = True self.is_compound = True
self.is_compound += self.raw_col.compound
self.opname = self.raw_col self.opname = self.raw_col
else: else:
self.sql = '\'' + node + '\'' if node != '*' else '*' self.sql = '\'' + node + '\'' if node != '*' else '*'
@ -341,9 +362,11 @@ class expr(ast_node):
exec(f'loc["{b}"] = lambda : "{b}"') exec(f'loc["{b}"] = lambda : "{b}"')
x = self.c_code if c_code is None else c_code x = self.c_code if c_code is None else c_code
from engine.utils import escape_qoutes
if decltypestr: if decltypestr:
return eval('f\'' + self.udf_decltypecall + '\'') return eval('f\'' + escape_qoutes(self.udf_decltypecall) + '\'')
return eval('f\'' + self.sql + '\'') self.sql.replace("'", "\\'")
return eval('f\'' + escape_qoutes(self.sql) + '\'')
if self.is_recursive_call_inudf or (self.need_decltypestr and self.is_udfexpr) or gettype: if self.is_recursive_call_inudf or (self.need_decltypestr and self.is_udfexpr) or gettype:
return call return call
else: else:

@ -16,7 +16,7 @@ class expr_base(ast_node, metaclass = abc.ABCMeta):
self.udf_map = self.context.udf_map self.udf_map = self.context.udf_map
self.func_maps = {**builtin_func, **self.udf_map, **user_module_func} self.func_maps = {**builtin_func, **self.udf_map, **user_module_func}
self.operators = {**builtin_operators, **self.udf_map, **user_module_func} self.operators = {**builtin_operators, **self.udf_map, **user_module_func}
self.narrow_funcs = ['sum', 'avg', 'count', 'min', 'max', 'last'] self.narrow_funcs = ['sum', 'avg', 'count', 'min', 'max', 'last', 'first']
def get_variable(self): def get_variable(self):
pass pass
@ -56,7 +56,7 @@ class expr_base(ast_node, metaclass = abc.ABCMeta):
raise ValueError(f'Parse Error: more than 1 entry in {node}.') raise ValueError(f'Parse Error: more than 1 entry in {node}.')
key, val = next(iter(node.items())) key, val = next(iter(node.items()))
if key in self.operators: if key in self.operators:
self.child_exprs = [__class__(self, v) for v in val] self.child_exprs = [self.__class__(self, v) for v in val]
self.process_child_nodes() self.process_child_nodes()
else: else:
self.process_non_operator(key, val) self.process_non_operator(key, val)

@ -59,7 +59,7 @@ class TableInfo:
cxt.tables_byname[self.table_name] = self # construct reverse map cxt.tables_byname[self.table_name] = self # construct reverse map
def add_cols(self, cols, new = True): def add_cols(self, cols, new = True):
for c in cols: for c in enlist(cols):
self.add_col(c, new) self.add_col(c, new)
def add_col(self, c, new = True): def add_col(self, c, new = True):

@ -76,12 +76,11 @@ __AQEXPORT__(void) init_session(Context* cxt);
#define __AQ_NO_SESSION__ __AQEXPORT__(void) init_session(Context*) {} #define __AQ_NO_SESSION__ __AQEXPORT__(void) init_session(Context*) {}
#ifdef _MSC_VER #ifdef _WIN32
void* _cdecl memcpy(void*, void*, size_t); #include <cstring>
#else #else
void* memcpy(void*, const void*, unsigned long long); void* memcpy(void*, const void*, unsigned long long);
#endif #endif
struct ColRef_storage { struct ColRef_storage {
void* container; void* container;
unsigned int capacity, size; unsigned int capacity, size;

@ -107,18 +107,26 @@ decayed_t<VT, T> maxw(uint32_t w, const VT<T>& arr) {
} }
template<class T, template<typename ...> class VT> template<class T, template<typename ...> class VT>
decayed_t<VT, types::GetFPType<T>> ratios(const VT<T>& arr) { decayed_t<VT, types::GetFPType<T>> ratiow(uint32_t w, const VT<T>& arr) {
uint32_t len = arr.size - 1; typedef std::decay_t<types::GetFPType<T>> FPType;
if (!arr.size) uint32_t len = arr.size;
if (arr.size <= w)
len = 1; len = 1;
decayed_t<VT, types::GetFPType<T>> ret(len); w = w > len ? len : w;
decayed_t<VT, FPType> ret(arr.size);
ret[0] = 0; ret[0] = 0;
for (uint32_t i = 0; i < w; ++i)
for (uint32_t i = 1; i < arr.size; ++i) ret[i] = arr[i] / (FPType)arr[0];
ret[i - 1] = arr[i] / arr[i - 1]; for (uint32_t i = w; i < arr.size; ++i)
ret[i] = arr[i] / (FPType) arr[i - w];
return ret; return ret;
} }
template<class T, template<typename ...> class VT>
decayed_t<VT, types::GetFPType<T>> ratios(const VT<T>& arr) {
return ratiow(1, arr);
}
template<class T, template<typename ...> class VT> template<class T, template<typename ...> class VT>
decayed_t<VT, types::GetLongType<T>> sums(const VT<T>& arr) { decayed_t<VT, types::GetLongType<T>> sums(const VT<T>& arr) {
const uint32_t& len = arr.size; const uint32_t& len = arr.size;
@ -129,6 +137,7 @@ decayed_t<VT, types::GetLongType<T>> sums(const VT<T>& arr) {
ret[i] = ret[i - 1] + arr[i]; ret[i] = ret[i - 1] + arr[i];
return ret; return ret;
} }
template<class T, template<typename ...> class VT> template<class T, template<typename ...> class VT>
decayed_t<VT, types::GetFPType<types::GetLongType<T>>> avgs(const VT<T>& arr) { decayed_t<VT, types::GetFPType<types::GetLongType<T>>> avgs(const VT<T>& arr) {
const uint32_t& len = arr.size; const uint32_t& len = arr.size;
@ -141,6 +150,7 @@ decayed_t<VT, types::GetFPType<types::GetLongType<T>>> avgs(const VT<T>& arr) {
ret[i] = (s += arr[i]) / (FPType)(i + 1); ret[i] = (s += arr[i]) / (FPType)(i + 1);
return ret; return ret;
} }
template<class T, template<typename ...> class VT> template<class T, template<typename ...> class VT>
decayed_t<VT, types::GetLongType<T>> sumw(uint32_t w, const VT<T>& arr) { decayed_t<VT, types::GetLongType<T>> sumw(uint32_t w, const VT<T>& arr) {
const uint32_t& len = arr.size; const uint32_t& len = arr.size;
@ -154,6 +164,7 @@ decayed_t<VT, types::GetLongType<T>> sumw(uint32_t w, const VT<T>& arr) {
ret[i] = ret[i - 1] + arr[i] - arr[i - w]; ret[i] = ret[i - 1] + arr[i] - arr[i - w];
return ret; return ret;
} }
template<class T, template<typename ...> class VT> template<class T, template<typename ...> class VT>
decayed_t<VT, types::GetFPType<types::GetLongType<T>>> avgw(uint32_t w, const VT<T>& arr) { decayed_t<VT, types::GetFPType<types::GetLongType<T>>> avgw(uint32_t w, const VT<T>& arr) {
typedef types::GetFPType<types::GetLongType<T>> FPType; typedef types::GetFPType<types::GetLongType<T>> FPType;
@ -209,6 +220,7 @@ template <class T> constexpr inline T maxw(uint32_t, const T& v) { return v; }
template <class T> constexpr inline T minw(uint32_t, const T& v) { return v; } template <class T> constexpr inline T minw(uint32_t, const T& v) { return v; }
template <class T> constexpr inline T avgw(uint32_t, const T& v) { return v; } template <class T> constexpr inline T avgw(uint32_t, const T& v) { return v; }
template <class T> constexpr inline T sumw(uint32_t, const T& v) { return v; } template <class T> constexpr inline T sumw(uint32_t, const T& v) { return v; }
template <class T> constexpr inline T ratiow(uint32_t, const T& v) { return 1; }
template <class T> constexpr inline T maxs(const T& v) { return v; } template <class T> constexpr inline T maxs(const T& v) { return v; }
template <class T> constexpr inline T mins(const T& v) { return v; } template <class T> constexpr inline T mins(const T& v) { return v; }
template <class T> constexpr inline T avgs(const T& v) { return v; } template <class T> constexpr inline T avgs(const T& v) { return v; }

@ -2,6 +2,7 @@
#include <type_traits> #include <type_traits>
#include <tuple> #include <tuple>
#include <functional>
#include "types.h" #include "types.h"
// only works for 64 bit systems // only works for 64 bit systems
constexpr size_t _FNV_offset_basis = 14695981039346656037ULL; constexpr size_t _FNV_offset_basis = 14695981039346656037ULL;
@ -21,7 +22,31 @@ inline size_t append_bytes(const astring_view& view) noexcept {
return append_bytes(view.str); return append_bytes(view.str);
} }
#ifdef __SIZEOF_INT128__
union int128_struct
{
struct {
uint64_t low, high;
}__struct;
__int128_t value = 0;
__uint128_t uvalue;
constexpr int128_struct() : value(0) {}
constexpr int128_struct(const __int128_t &value) noexcept : value(value) {}
constexpr int128_struct(const __uint128_t &value) noexcept : uvalue(value) {}
operator __int128_t () const {
return value;
}
operator __uint128_t () const {
return uvalue;
}
operator __int128_t& () {
return value;
}
operator __uint128_t& () {
return uvalue;
}
};
#endif
template <class ...Types> template <class ...Types>
struct hasher { struct hasher {
template <size_t i = 0> typename std::enable_if< i == sizeof...(Types), template <size_t i = 0> typename std::enable_if< i == sizeof...(Types),
@ -32,8 +57,15 @@ struct hasher {
template <size_t i = 0> typename std::enable_if < i < sizeof ...(Types), template <size_t i = 0> typename std::enable_if < i < sizeof ...(Types),
size_t>::type hashi(const std::tuple<Types...>& record) const { size_t>::type hashi(const std::tuple<Types...>& record) const {
using current_type = typename std::decay<typename std::tuple_element<i, std::tuple<Types...>>::type>::type; using current_type = typename std::decay<typename std::tuple_element<i, std::tuple<Types...>>::type>::type;
#ifdef __SIZEOF_INT128__
return std::hash<current_type>()(std::get<i>(record)) ^ hashi<i + 1>(record); using _current_type = typename std::conditional_t<
std::is_same_v<current_type, __uint128_t> ||
std::is_same_v<current_type, __int128_t>,
int128_struct, current_type>;
#else
#define _current_type current_type
#endif
return std::hash<_current_type>()(std::get<i>(record)) ^ hashi<i + 1>(record);
} }
size_t operator()(const std::tuple<Types...>& record) const { size_t operator()(const std::tuple<Types...>& record) const {
return hashi(record); return hashi(record);
@ -75,7 +107,15 @@ namespace std{
std::hash<types::time_t>()(_Keyval.time); std::hash<types::time_t>()(_Keyval.time);
} }
}; };
#ifdef __SIZEOF_INT128__
template<>
struct hash<int128_struct>{
size_t operator() (const int128_struct& _Keyval) const noexcept {
return std::hash<uint64_t>()(_Keyval.__struct.low) ^ std::hash<uint64_t>()(_Keyval.__struct.high);
}
};
#endif
template <class ...Types> template <class ...Types>
struct hash<std::tuple<Types...>> : public hasher<Types...>{ }; struct hash<std::tuple<Types...>> : public hasher<Types...>{ };

@ -265,16 +265,16 @@ string base62uuid(int l) {
} }
template<typename _Ty> // template<typename _Ty>
inline void vector_type<_Ty>::out(uint32_t n, const char* sep) const // inline void vector_type<_Ty>::out(uint32_t n, const char* sep) const
{ // {
n = n > size ? size : n; // n = n > size ? size : n;
std::cout << '('; // std::cout << '(';
{ // {
uint32_t i = 0; // uint32_t i = 0;
for (; i < n - 1; ++i) // for (; i < n - 1; ++i)
std::cout << this->operator[](i) << sep; // std::cout << this->operator[](i) << sep;
std::cout << this->operator[](i); // std::cout << this->operator[](i);
} // }
std::cout << ')'; // std::cout << ')';
} // }

@ -176,10 +176,10 @@ int dll_main(int argc, char** argv, Context* cxt){
//getlasterror //getlasterror
if (!user_module_handle) if (!user_module_handle)
#ifndef _MSC_VER #ifndef _WIN32
puts(dlerror()); puts(dlerror());
#else #else
printf("Fatal Error: Module %s failed to load with error code %d.\n", mname, GetLastError()); printf("Fatal Error: Module %s failed to load with error code %d.\n", mname, dlerror());
#endif #endif
user_module_map[mname] = user_module_handle; user_module_map[mname] = user_module_handle;
initialize_module(mname, user_module_handle, cxt); initialize_module(mname, user_module_handle, cxt);

@ -129,8 +129,8 @@ public:
} }
// defined in table_ext_monetdb.hpp // defined in table_ext_monetdb.hpp
void* monetdb_get_col(); void* monetdb_get_col(void** gc_vecs, uint32_t& cnt);
}; };
template<> template<>
class ColRef<void> : public ColRef<int> {}; class ColRef<void> : public ColRef<int> {};
@ -391,11 +391,11 @@ struct TableInfo {
constexpr auto num_date = count_type<types::date_t>((tuple_type*)(0)); constexpr auto num_date = count_type<types::date_t>((tuple_type*)(0));
constexpr auto num_time = count_type<types::time_t>((tuple_type*)(0)); constexpr auto num_time = count_type<types::time_t>((tuple_type*)(0));
constexpr auto num_timestamp = count_type<types::timestamp_t>((tuple_type*)(0)); constexpr auto num_timestamp = count_type<types::timestamp_t>((tuple_type*)(0));
char cbuf[num_hge * 41 char cbuf[ num_hge * 41
+ num_time * types::time_t::string_length() + num_time * types::time_t::string_length()
+ num_date * types::date_t::string_length() + num_date * types::date_t::string_length()
+ num_timestamp * types::timestamp_t::string_length() + num_timestamp * types::timestamp_t::string_length()
+ 1 + 1 // padding for msvc not allowing empty arrays
]; ];
setgbuf(cbuf); setgbuf(cbuf);
if (view) if (view)
@ -625,106 +625,164 @@ inline void TableInfo<Types...>::print(const char* __restrict sep, const char* _
std::cout << end; std::cout << end;
} }
} }
template <class T1, class T2, template<typename ...> class VT, template<typename ...> class VT2> template <class T1,
decayed_t<VT, typename types::Coercion<T1, T2>::type> operator -(const VT<T1>& lhs, const VT2<T2>& rhs) { template<typename> class VT,
auto ret = decayed_t<VT, typename types::Coercion<T1, T2>::type>(lhs.size); class TRet>
using test_vt_support = typename std::enable_if_t<std::is_same_v<VT<T1>, ColRef<T1>> ||
std::is_same_v<VT<T1>, ColView<T1>> ||
std::is_same_v<VT<T1>, vector_type<T1>>, TRet>;
template <class T1, class T2,
template<typename> class VT>
using get_autoext_type = test_vt_support<T1, VT,
decayed_t<VT, typename types::Coercion<T1, T2>::type>>;
template <class T1, class T2,
template<typename> class VT>
using get_long_type = test_vt_support<T1, VT,
decayed_t<VT, types::GetLongType<typename types::Coercion<T1, T2>::type>>>;
template <class T1, class T2,
template<typename> class VT>
using get_fp_type = test_vt_support<T1, VT,
decayed_t<VT, types::GetFPType<typename types::Coercion<T1, T2>::type>>>;
template <class T1,
template<typename> class VT, template<typename> class VT2,
class TRet>
using test_vt_support2 = typename std::enable_if_t<(std::is_same_v<VT<T1>, ColRef<T1>> ||
std::is_same_v<VT<T1>, ColView<T1>> ||
std::is_same_v<VT<T1>, vector_type<T1>>) &&
(std::is_same_v<VT2<T1>, ColRef<T1>> ||
std::is_same_v<VT2<T1>, ColView<T1>> ||
std::is_same_v<VT2<T1>, vector_type<T1>>), TRet >;
template <class T1, class T2,
template<typename> class VT, template<typename> class VT2>
using get_autoext_type2 = test_vt_support2<T1, VT, VT2,
decayed_t<VT, typename types::Coercion<T1, T2>::type>>;
template <class T1, class T2,
template<typename> class VT, template<typename> class VT2>
using get_long_type2 = test_vt_support2<T1, VT, VT2,
decayed_t<VT, types::GetLongType<typename types::Coercion<T1, T2>::type>>>;
template <class T1, class T2,
template<typename> class VT, template<typename> class VT2>
using get_fp_type2 = test_vt_support2<T1, VT, VT2,
decayed_t<VT, types::GetFPType<typename types::Coercion<T1, T2>::type>>>;
template <class T1, class T2, template<typename> class VT, template<typename> class VT2>
get_autoext_type2<T1, T2, VT, VT2>
operator -(const VT<T1>& lhs, const VT2<T2>& rhs) {
auto ret = get_autoext_type2<T1, T2, VT, VT2>(lhs.size);
for (uint32_t i = 0; i < lhs.size; ++i) for (uint32_t i = 0; i < lhs.size; ++i)
ret[i] = lhs[i] - rhs[i]; ret[i] = lhs[i] - rhs[i];
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT> template <class T1, class T2, template<typename> class VT>
decayed_t<VT, typename types::Coercion<T1, T2>::type> operator -(const VT<T1>& lhs, const T2& rhs) { get_autoext_type<T1, T2, VT>
auto ret = decayed_t<VT, typename types::Coercion<T1, T2>::type>(lhs.size); operator -(const VT<T1>& lhs, const T2& rhs) {
auto ret = get_autoext_type<T1, T2, VT>(lhs.size);
for (uint32_t i = 0; i < lhs.size; ++i) for (uint32_t i = 0; i < lhs.size; ++i)
ret[i] = lhs[i] - rhs; ret[i] = lhs[i] - rhs;
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT> template <class T1, class T2, template<typename> class VT>
decayed_t<VT, typename types::Coercion<T1, T2>::type> operator -(const T2& lhs, const VT<T1>& rhs) { get_autoext_type<T1, T2, VT>
auto ret = decayed_t<VT, typename types::Coercion<T1, T2>::type>(rhs.size); operator -(const T2& lhs, const VT<T1>& rhs) {
auto ret = get_autoext_type<T1, T2, VT>(rhs.size);
for (uint32_t i = 0; i < rhs.size; ++i) for (uint32_t i = 0; i < rhs.size; ++i)
ret[i] = lhs - rhs[i]; ret[i] = lhs - rhs[i];
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT, template<typename ...> class VT2> template <class T1, class T2, template<typename> class VT, template<typename> class VT2>
decayed_t<VT, typename types::Coercion<T1, T2>::type> operator +(const VT<T1>& lhs, const VT2<T2>& rhs) { get_autoext_type2<T1, T2, VT, VT2>
auto ret = decayed_t<VT, typename types::Coercion<T1, T2>::type>(lhs.size); operator +(const VT<T1>& lhs, const VT2<T2>& rhs) {
auto ret = get_autoext_type2<T1, T2, VT, VT2>(lhs.size);
for (uint32_t i = 0; i < lhs.size; ++i) for (uint32_t i = 0; i < lhs.size; ++i)
ret[i] = lhs[i] + rhs[i]; ret[i] = lhs[i] + rhs[i];
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT> template <class T1, class T2, template<typename> class VT>
decayed_t<VT, typename types::Coercion<T1, T2>::type> operator +(const VT<T1>& lhs, const T2& rhs) { get_autoext_type<T1, T2, VT>
auto ret = decayed_t<VT, typename types::Coercion<T1, T2>::type>(lhs.size); operator +(const VT<T1>& lhs, const T2& rhs) {
auto ret = get_autoext_type<T1, T2, VT>(lhs.size);
for (uint32_t i = 0; i < lhs.size; ++i) for (uint32_t i = 0; i < lhs.size; ++i)
ret[i] = lhs[i] + rhs; ret[i] = lhs[i] + rhs;
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT> template <class T1, class T2, template<typename> class VT>
decayed_t<VT, typename types::Coercion<T1, T2>::type> operator +(const T2& lhs, const VT<T1>& rhs) { get_autoext_type<T1, T2, VT>
auto ret = decayed_t<VT, typename types::Coercion<T1, T2>::type>(rhs.size); operator +(const T2& lhs, const VT<T1>& rhs) {
auto ret = get_autoext_type<T1, T2, VT> (rhs.size);
for (uint32_t i = 0; i < rhs.size; ++i) for (uint32_t i = 0; i < rhs.size; ++i)
ret[i] = lhs + rhs[i]; ret[i] = lhs + rhs[i];
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT, template<typename ...> class VT2> template <class T1, class T2, template<typename> class VT, template<typename> class VT2>
decayed_t<VT, typename types::Coercion<T1, T2>::type> operator *(const VT<T1>& lhs, const VT2<T2>& rhs) { get_long_type2<T1, T2, VT, VT2>
auto ret = decayed_t<VT, typename types::Coercion<T1, T2>::type>(lhs.size); operator *(const VT<T1>& lhs, const VT2<T2>& rhs) {
auto ret = get_long_type2<T1, T2, VT, VT2>(lhs.size);
for (uint32_t i = 0; i < lhs.size; ++i) for (uint32_t i = 0; i < lhs.size; ++i)
ret[i] = lhs[i] * rhs[i]; ret[i] = lhs[i] * rhs[i];
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT> template <class T1, class T2, template<typename> class VT>
decayed_t<VT, typename types::Coercion<T1, T2>::type> operator *(const VT<T1>& lhs, const T2& rhs) { get_long_type<T1, T2, VT>
auto ret = decayed_t<VT, typename types::Coercion<T1, T2>::type>(lhs.size); operator *(const VT<T1>& lhs, const T2& rhs) {
auto ret = get_long_type<T1, T2, VT>(lhs.size);
for (uint32_t i = 0; i < lhs.size; ++i) for (uint32_t i = 0; i < lhs.size; ++i)
ret[i] = lhs[i] * rhs; ret[i] = lhs[i] * rhs;
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT> template <class T1, class T2, template<typename> class VT>
decayed_t<VT, typename types::Coercion<T1, T2>::type> operator *(const T2& lhs, const VT<T1>& rhs) { get_long_type<T1, T2, VT>
auto ret = decayed_t<VT, typename types::Coercion<T1, T2>::type>(rhs.size); operator *(const T2& lhs, const VT<T1>& rhs) {
auto ret = get_long_type<T1, T2, VT>(rhs.size);
for (uint32_t i = 0; i < rhs.size; ++i) for (uint32_t i = 0; i < rhs.size; ++i)
ret[i] = lhs * rhs[i]; ret[i] = lhs * rhs[i];
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT, template<typename ...> class VT2> template <class T1, class T2, template<typename> class VT, template<typename> class VT2>
decayed_t<VT, types::GetFPType<typename types::Coercion<T1, T2>::type>> operator /(const VT<T1>& lhs, const VT2<T2>& rhs) { get_fp_type2<T1, T2, VT, VT2>
auto ret = decayed_t<VT, types::GetFPType<typename types::Coercion<T1, T2>::type>>(lhs.size); operator /(const VT<T1>& lhs, const VT2<T2>& rhs) {
auto ret = get_fp_type2<T1, T2, VT, VT2>(lhs.size);
for (uint32_t i = 0; i < lhs.size; ++i) for (uint32_t i = 0; i < lhs.size; ++i)
ret[i] = lhs[i] / rhs[i]; ret[i] = lhs[i] / rhs[i];
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT> template <class T1, class T2, template<typename> class VT>
decayed_t<VT, types::GetFPType<typename types::Coercion<T1, T2>::type>> operator /(const VT<T1>& lhs, const T2& rhs) { get_fp_type<T1, T2, VT>
auto ret = decayed_t<VT, types::GetFPType<typename types::Coercion<T1, T2>::type>>(lhs.size); operator /(const VT<T1>& lhs, const T2& rhs) {
auto ret = get_fp_type<T1, T2, VT>(lhs.size);
for (uint32_t i = 0; i < lhs.size; ++i) for (uint32_t i = 0; i < lhs.size; ++i)
ret[i] = lhs[i] / rhs; ret[i] = lhs[i] / rhs;
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT> template <class T1, class T2, template<typename> class VT>
decayed_t<VT, types::GetFPType<typename types::Coercion<T1, T2>::type>> operator /(const T2& lhs, const VT<T1>& rhs) { get_fp_type<T1, T2, VT>
auto ret = decayed_t<VT, types::GetFPType<typename types::Coercion<T1, T2>::type>>(rhs.size); operator /(const T2& lhs, const VT<T1>& rhs) {
auto ret = get_fp_type<T1, T2, VT>(rhs.size);
for (uint32_t i = 0; i < rhs.size; ++i) for (uint32_t i = 0; i < rhs.size; ++i)
ret[i] = lhs / rhs[i]; ret[i] = lhs / rhs[i];
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT, template<typename ...> class VT2> template <class T1, class T2, template<typename> class VT, template<typename> class VT2>
VT<bool> operator >(const VT<T1>& lhs, const VT2<T2>& rhs) { VT<bool> operator >(const VT<T1>& lhs, const VT2<T2>& rhs) {
auto ret = VT<bool>(lhs.size); auto ret = VT<bool>(lhs.size);
for (uint32_t i = 0; i < lhs.size; ++i) for (uint32_t i = 0; i < lhs.size; ++i)
ret[i] = lhs[i] > rhs[i]; ret[i] = lhs[i] > rhs[i];
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT> template <class T1, class T2, template<typename> class VT>
VT<bool> operator >(const VT<T1>& lhs, const T2& rhs) { VT<bool> operator >(const VT<T1>& lhs, const T2& rhs) {
auto ret = VT<bool>(lhs.size); auto ret = VT<bool>(lhs.size);
for (uint32_t i = 0; i < lhs.size; ++i) for (uint32_t i = 0; i < lhs.size; ++i)
ret[i] = lhs[i] > rhs; ret[i] = lhs[i] > rhs;
return ret; return ret;
} }
template <class T1, class T2, template<typename ...> class VT> template <class T1, class T2, template<typename> class VT>
VT<bool> operator >(const T2& lhs, const VT<T1>& rhs) { VT<bool> operator >(const T2& lhs, const VT<T1>& rhs) {
auto ret = VT<bool>(rhs.size); auto ret = VT<bool>(rhs.size);
for (uint32_t i = 0; i < rhs.size; ++i) for (uint32_t i = 0; i < rhs.size; ++i)

@ -22,7 +22,12 @@ inline constexpr monetdbe_types AQType_2_monetdbe[] = {
#else #else
monetdbe_int64_t, monetdbe_int64_t,
#endif #endif
monetdbe_int16_t, monetdbe_int8_t, monetdbe_bool, monetdbe_int64_t, monetdbe_int16_t, monetdbe_int8_t, monetdbe_bool,
#ifdef HAVE_HGE
monetdbe_int128_t,
#else
monetdbe_int64_t,
#endif
monetdbe_timestamp, monetdbe_int64_t, monetdbe_int64_t monetdbe_timestamp, monetdbe_int64_t, monetdbe_int64_t
}; };
@ -35,19 +40,22 @@ void TableInfo<Ts ...>::monetdb_append_table(void* srv, const char* alt_name) {
monetdbe_column** monetdbe_cols = new monetdbe_column * [sizeof...(Ts)]; monetdbe_column** monetdbe_cols = new monetdbe_column * [sizeof...(Ts)];
uint32_t i = 0; uint32_t i = 0;
constexpr auto n_vecs = count_vector_type((tuple_type*)(0));
void* gc_vecs[1 + n_vecs];
puts("getcols..."); puts("getcols...");
const auto get_col = [&monetdbe_cols, &i, *this](auto v) { uint32_t cnt = 0;
const auto get_col = [&monetdbe_cols, &i, *this, &gc_vecs, &cnt](auto v) {
printf("%d %d\n", i, (ColRef<void>*)v - colrefs); printf("%d %d\n", i, (ColRef<void>*)v - colrefs);
monetdbe_cols[i++] = (monetdbe_column*)v->monetdb_get_col(); monetdbe_cols[i++] = (monetdbe_column*)v->monetdb_get_col(gc_vecs, cnt);
}; };
(get_col((ColRef<Ts>*)(colrefs + i)), ...); (get_col((ColRef<Ts>*)(colrefs + i)), ...);
puts("getcols done"); puts("getcols done");
for(int i = 0; i < sizeof...(Ts); ++i) for(int i = 0; i < sizeof...(Ts); ++i)
{ {
printf("no:%d name: %s count:%d data: %p \n", printf("no:%d name: %s count:%d data: %p type:%d \n",
i, monetdbe_cols[i]->name, monetdbe_cols[i]->count, monetdbe_cols[i]->data); i, monetdbe_cols[i]->name, monetdbe_cols[i]->count, monetdbe_cols[i]->data, monetdbe_cols[i]->type);
} }
std::string create_table_str = "CREATE TABLE "; std::string create_table_str = "CREATE TABLE IF NOT EXISTS ";
create_table_str += alt_name; create_table_str += alt_name;
create_table_str += " ("; create_table_str += " (";
i = 0; i = 0;
@ -70,12 +78,14 @@ void TableInfo<Ts ...>::monetdb_append_table(void* srv, const char* alt_name) {
return; return;
} }
} }
// for(uint32_t i = 0; i < n_vecs; ++i)
// free(gc_vecs[i]);
puts("Error! Empty table."); puts("Error! Empty table.");
} }
template<class Type> template<class Type>
void* ColRef<Type>::monetdb_get_col() { void* ColRef<Type>::monetdb_get_col(void** gc_vecs, uint32_t& cnt) {
auto aq_type = AQType_2_monetdbe[types::Types<Type>::getType()]; auto aq_type = AQType_2_monetdbe[types::Types<Type>::getType()];
monetdbe_column* col = (monetdbe_column*)malloc(sizeof(monetdbe_column)); monetdbe_column* col = (monetdbe_column*)malloc(sizeof(monetdbe_column));
@ -83,7 +93,13 @@ void* ColRef<Type>::monetdb_get_col() {
col->count = this->size; col->count = this->size;
col->data = this->container; col->data = this->container;
col->name = const_cast<char*>(this->name); col->name = const_cast<char*>(this->name);
// auto arr = (types::timestamp_t*) malloc (sizeof(types::timestamp_t)* this->size);
// if constexpr (is_vector_type<Type>){
// for(uint32_t i = 0; i < this->size; ++i){
// memcpy(arr + i, this->container + i, sizeof(types::timestamp_t));
// }
// gc_vecs[cnt++] = arr;
// }
return col; return col;
} }

@ -3,6 +3,7 @@
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include <tuple> #include <tuple>
using std::size_t;
#if defined(__SIZEOF_INT128__) and not defined(_WIN32) #if defined(__SIZEOF_INT128__) and not defined(_WIN32)
#define __AQ__HAS__INT128__ #define __AQ__HAS__INT128__
@ -29,9 +30,9 @@ namespace types {
static constexpr const char* printf_str[] = { "%d", "%f", "%s", "%lf", "%Lf", "%ld", "%d", "%hi", "%s", "%s", "%c", static constexpr const char* printf_str[] = { "%d", "%f", "%s", "%lf", "%Lf", "%ld", "%d", "%hi", "%s", "%s", "%c",
"%u", "%lu", "%s", "%hu", "%hhu", "%s", "%s", "Vector<%s>", "%s", "NULL", "ERROR" }; "%u", "%lu", "%s", "%hu", "%hhu", "%s", "%s", "Vector<%s>", "%s", "NULL", "ERROR" };
static constexpr const char* SQL_Type[] = { "INT", "REAL", "TEXT", "DOUBLE", "DOUBLE", "BIGINT", "HUGEINT", "SMALLINT", "DATE", "TIME", "TINYINT", static constexpr const char* SQL_Type[] = { "INT", "REAL", "TEXT", "DOUBLE", "DOUBLE", "BIGINT", "HUGEINT", "SMALLINT", "DATE", "TIME", "TINYINT",
"INT", "BIGINT", "HUGEINT", "SMALLINT", "TINYINT", "BOOL", "BLOB", "TIMESTAMP", "NULL", "ERROR" }; "INT", "BIGINT", "HUGEINT", "SMALLINT", "TINYINT", "BOOL", "HUGEINT", "TIMESTAMP", "NULL", "ERROR"};
// TODO: deal with data/time <=> str/uint conversion // TODO: deal with data/time <=> str/uint conversion
struct date_t { struct date_t {
unsigned char day = 0; unsigned char day = 0;
@ -168,23 +169,22 @@ namespace types {
template<class T> template<class T>
using GetLongType = typename GetLongTypeImpl<typename std::decay<T>::type>::type; using GetLongType = typename GetLongTypeImpl<typename std::decay<T>::type>::type;
template<class T> template<class T>
struct GetLongerTypeImpl { struct GetLongerTypeImpl {
using type = Cond( using type = Cond(
__U(T), Cond(__Eq(char), unsigned short, __U(T), Cond(__Eq(char), unsigned short,
Cond(__Eq(short), unsigned int, Cond(__Eq(short), unsigned int,
Cond(__Eq(int), unsigned long long, Cond(__Eq(int), unsigned long long,
ULL_Type ULL_Type
))), ))),
Cond(Fp(T), double, Cond(Fp(T), double,
Cond(__Eq(char), short, Cond(__Eq(char), short,
Cond(__Eq(short), int, Cond(__Eq(short), int,
Cond(__Eq(int), long, Cond(__Eq(int), long,
LL_Type LL_Type
)))) ))))
); );
@ -194,22 +194,22 @@ namespace types {
} }
struct astring_view { union astring_view {
const unsigned char* str = 0; const unsigned char* str = 0;
const signed char* sstr;
#if defined(__clang__) || !defined(__GNUC__) const char* rstr;
size_t ptr;
constexpr
astring_view(const char* str) noexcept :
rstr(str) {}
constexpr constexpr
#endif astring_view(const signed char* str) noexcept :
astring_view(const char* str) noexcept : sstr(str) {}
str((const unsigned char*)(str)) {}
#if defined(__clang__) || !defined(__GNUC__)
constexpr
#endif
astring_view(const signed char* str) noexcept :
str((const unsigned char*)(str)) {}
constexpr constexpr
astring_view(const unsigned char* str) noexcept : astring_view(const unsigned char* str) noexcept :
str(str) {} str(str) {}
constexpr astring_view() noexcept = default; constexpr astring_view() noexcept = default;
@ -224,17 +224,28 @@ struct astring_view {
} }
return !(*this_str || *other_str); return !(*this_str || *other_str);
} }
bool operator >(const astring_view& r) const { bool operator >(const astring_view&r) const{
auto this_str = str;
auto other_str = r.str;
bool ret = true;
while (*this_str && *other_str) {
if (*this_str <= *other_str)
ret = false;
this_str++;
other_str++;
}
return (*this_str && !*other_str) ||
(ret && !*this_str && *other_str);
} }
operator const char* () const { operator const char* () const {
return reinterpret_cast<const char*>(str); return rstr;
} }
operator const unsigned char* () const { operator const unsigned char* () const {
return reinterpret_cast<const unsigned char*>(str); return str;
} }
operator const signed char* () const { operator const signed char* () const {
return reinterpret_cast<const signed char*>(str); return sstr;
} }
}; };
@ -373,4 +384,10 @@ constexpr size_t count_type(std::tuple<Types...>* ts) {
size_t t[] = { sum_type<Types, T1...>() ... }; size_t t[] = { sum_type<Types, T1...>() ... };
return sum_type(t, sizeof...(Types)); return sum_type(t, sizeof...(Types));
} }
template<class ...Types>
constexpr size_t count_vector_type(std::tuple<Types...>* ts) {
size_t t[] = {is_vector_type<Types> ...};
return sum_type(t, sizeof...(Types));
}
#endif // !_TYPES_H #endif // !_TYPES_H

@ -12,11 +12,16 @@
#include <iterator> #include <iterator>
#include <initializer_list> #include <initializer_list>
#include <unordered_set> #include <unordered_set>
#include <iostream>
#include "hasher.h" #include "hasher.h"
#include "types.h" #include "types.h"
#pragma pack(push, 1) #pragma pack(push, 1)
template <typename _Ty> template <typename _Ty>
class slim_vector {
};
template <typename _Ty>
class vector_type { class vector_type {
public: public:
typedef vector_type<_Ty> Decayed_t; typedef vector_type<_Ty> Decayed_t;
@ -249,7 +254,25 @@ public:
} }
size = this->size + dist; size = this->size + dist;
} }
void out(uint32_t n = 4, const char* sep = " ") const; inline void out(uint32_t n = 4, const char* sep = " ") const
{
const char* more = "";
if (n < this->size)
more = " ... ";
else
n = this->size;
std::cout << '(';
if (n > 0)
{
uint32_t i = 0;
for (; i < n - 1; ++i)
std::cout << this->operator[](i) << sep;
std::cout << this->operator[](i);
}
std::cout<< more;
std::cout << ')';
}
vector_type<_Ty> subvec_memcpy(uint32_t start, uint32_t end) const { vector_type<_Ty> subvec_memcpy(uint32_t start, uint32_t end) const {
vector_type<_Ty> subvec(end - start); vector_type<_Ty> subvec(end - start);
memcpy(subvec.container, container + start, sizeof(_Ty) * (end - start)); memcpy(subvec.container, container + start, sizeof(_Ty) * (end - start));

@ -20,6 +20,10 @@ int dlclose(void* handle)
return FreeLibrary(static_cast<HMODULE>(handle)); return FreeLibrary(static_cast<HMODULE>(handle));
} }
int dlerror() {
return GetLastError();
}
SharedMemory::SharedMemory(const char* fname) SharedMemory::SharedMemory(const char* fname)
{ {
this->hFileMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 2, fname); this->hFileMap = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 2, fname);

@ -5,6 +5,8 @@ static constexpr int RTLD_LAZY = 1;
void* dlopen(const char*, int); void* dlopen(const char*, int);
void* dlsym(void*, const char*); void* dlsym(void*, const char*);
int dlclose(void*); int dlclose(void*);
int dlerror();
struct SharedMemory struct SharedMemory
{ {
void* hFileMap; void* hFileMap;

Binary file not shown.

@ -43,5 +43,4 @@ SELECT ID, avgs(10, ClosePrice)
FROM td NATURAL JOIN FROM td NATURAL JOIN
HistoricQuotes HistoricQuotes
ASSUMING ASC TradeDate ASSUMING ASC TradeDate
GROUP BY ID GROUP BY ID
ORDER BY ID

@ -10,4 +10,3 @@ FROM network
ASSUMING ASC src, ASC dst, ASC _time ASSUMING ASC src, ASC dst, ASC _time
GROUP BY src, dst, sums (deltas(_time) > 120) GROUP BY src, dst, sums (deltas(_time) > 120)

Loading…
Cancel
Save