├── .github └── workflows │ ├── deploy.yml │ └── dotnet.yml ├── .gitignore ├── Directory.Build.props ├── LICENSE ├── README.md ├── chdb-dotnet.png ├── chdb.png ├── chdb.sln ├── src ├── chdb-meta │ └── chdb-meta.csproj ├── chdb-tool │ ├── Program.cs │ └── chdb-tool.csproj └── chdb │ ├── ChDb.cs │ ├── LocalResult.cs │ ├── Session.cs │ └── chdb.csproj ├── test └── ChDbTest │ ├── ChDbTest.cs │ ├── GlobalUsings.cs │ └── test.csproj └── update_libchdb.sh /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: publish dotnet packages 2 | 3 | on: 4 | release: 5 | types: [ created ] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | packages: write 12 | contents: read 13 | steps: 14 | - name: Checkout the repository 15 | uses: actions/checkout@v4 16 | - name: Setup .NET Core 8.x 17 | uses: actions/setup-dotnet@v3 18 | with: 19 | dotnet-version: | 20 | 6.x 21 | 8.x 22 | cache: true 23 | - name: Download chdb library 24 | run: ./update_libchdb.sh 25 | - run: dotnet build --configuration Release 26 | - name: Create the packages 27 | run: dotnet pack --configuration Release --include-symbols 28 | - name: Publish the package to nuget.org 29 | run: dotnet nuget push nupkg/*.nupkg -k $NUGET_AUTH_TOKEN -s https://api.nuget.org/v3/index.json 30 | env: 31 | NUGET_AUTH_TOKEN: ${{secrets.NUGET_TOKEN}} 32 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a .NET project 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net 3 | 4 | name: build 5 | 6 | env: 7 | DOTNET_NOLOGO: 1 8 | DOTNET_CLI_TELEMETRY_OPTOUT: 1 9 | 10 | on: 11 | push: 12 | branches: [ "main" ] 13 | pull_request: 14 | branches: [ "main" ] 15 | workflow_dispatch: 16 | inputs: 17 | reason: 18 | description: 'The reason for running the workflow' 19 | required: true 20 | default: 'Manual run' 21 | 22 | jobs: 23 | build_chdb: 24 | name: Build chdb-${{ matrix.rid }} 25 | runs-on: ${{ matrix.os }} 26 | strategy: 27 | matrix: 28 | include: 29 | - os: ubuntu-latest 30 | rid: linux-x64 31 | - os: macos-latest 32 | rid: osx-x64 33 | - os: macos-14 34 | rid: osx-arm64 35 | 36 | steps: 37 | - name: 'Print manual run reason' 38 | if: ${{ github.event_name == 'workflow_dispatch' }} 39 | run: | 40 | echo 'Reason: ${{ github.event.inputs.reason }}' 41 | 42 | - uses: actions/checkout@v4 43 | 44 | - name: Setup .NET Core 45 | uses: actions/setup-dotnet@v3 46 | with: 47 | dotnet-version: | 48 | 6.0.x 49 | 8.0.x 50 | source-url: https://nuget.pkg.github.com/vilinski/index.json 51 | env: 52 | NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} 53 | - name: Display dotnet version 54 | run: | 55 | dotnet --version 56 | echo "GITHUB_WORKSPACE $GITHUB_WORKSPACE" 57 | echo "GITHUB_ACTION $GITHUB_ACTION" 58 | echo "GITHUB_RUN_ID $GITHUB_RUN_ID" 59 | echo "GITHUB_RUN_NUMBER $GITHUB_RUN_NUMBER" 60 | 61 | - name: Restore 62 | run: dotnet restore 63 | 64 | - name: Download chdb library 65 | run: ./update_libchdb.sh 66 | 67 | - name: Build 68 | run: | 69 | # copy to the correct location 70 | cp libchdb.so src/chdb/libchdb.so 71 | ls -lahS src/chdb/libchdb* 72 | dotnet build --no-restore --configuration Release 73 | 74 | - name: Test 75 | run: dotnet test -c Release /p:TestTfmsInParallel=false --logger "console;verbosity=detailed" --no-build --logger trx --results-directory "TestResults-${{ matrix.rid }}" 76 | 77 | # - name: Upload dotnet test results 78 | # uses: actions/upload-artifact@v4 79 | # with: 80 | # name: dotnet-results-${{ matrix.rid }} 81 | # path: TestResults-${{ matrix.rid }} 82 | # # Use always() to always run this step to publish test results when there are test failures 83 | # if: ${{ always() }} 84 | 85 | # - name: Pack chdb-${{ matrix.rid }} 86 | # run: | 87 | # dotnet pack src/chdb/chdb.csproj -c Release 88 | # ls -lahS nupkg 89 | 90 | # - name: Publish the package to nuget.org 91 | # run: dotnet nuget push nupkg/*.nupkg --skip-duplicate --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_AUTH_TOKEN_CHDB }} 92 | # env: 93 | # NUGET_AUTH_TOKEN: ${{ secrets.NUGET_AUTH_TOKEN_CHDB }} 94 | 95 | # - name: Publish chdb-${{ matrix.rid }} package to GPR 96 | # run: dotnet nuget push nupkg/chdb-${{ matrix.rid }}.*.nupkg --skip-duplicate --api-key ${{ secrets.PACKAGES_TOKEN }} --source https://nuget.pkg.github.com/chdb-io/index.json 97 | # env: 98 | # NUGET_AUTH_TOKEN: ${{ secrets.PACKAGES_TOKEN }} 99 | 100 | # - name: Upload nupkg 101 | # #run: ls -l nupkg/*.nupkg 102 | # uses: actions/upload-artifact@v4 103 | # with: 104 | # name: dotnet-nupkg-${{ matrix.rid }} 105 | # path: nupkg 106 | 107 | push_chdb: 108 | if: github.event.pull_request.merged 109 | name: Push chdb 110 | needs: build_chdb 111 | runs-on: ubuntu-latest 112 | steps: 113 | 114 | - uses: actions/checkout@v4 115 | 116 | - name: Download chdb library 117 | run: ./update_libchdb.sh 118 | 119 | # - name: Upload libchdb Artifact 120 | # uses: actions/upload-artifact@v4 121 | # with: 122 | # name: libchdb 123 | # path: libchdb.so 124 | 125 | - name: Pack 126 | run: | 127 | cp libchdb.so src/chdb/libchdb.so 128 | ls -lahS src/chdb/libchdb* 129 | dotnet pack src/chdb/chdb.csproj -c Release --include-symbols 130 | ls -lahS nupkg 131 | 132 | - name: Publish the package to nuget.org 133 | run: dotnet nuget push nupkg/chdb.*.nupkg --skip-duplicate --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_AUTH_TOKEN_CHDB }} 134 | 135 | 136 | push_tool: 137 | if: github.event.pull_request.merged 138 | name: Push chdb-tool 139 | needs: push_chdb 140 | runs-on: ubuntu-latest 141 | env: 142 | PUSH_TOOL: true 143 | steps: 144 | - uses: actions/checkout@v4 145 | 146 | - name: Download chdb library 147 | run: ./update_libchdb.sh 148 | 149 | - name: Pack 150 | run: | 151 | ls -lahS . 152 | ls -lahS src/chdb/* 153 | cp libchdb.so src/chdb/ 154 | ls -lahS src/chdb/libchdb* 155 | dotnet nuget sources add -n chdb ./nupkg 156 | dotnet pack src/chdb-tool/chdb-tool.csproj -c Release --include-symbols 157 | ls -lahS nupkg 158 | 159 | - name: Publish 160 | run: dotnet nuget push nupkg/chdb-tool.*.nupkg --skip-duplicate --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.NUGET_AUTH_TOKEN_CHDB }} 161 | 162 | - name: Test chdb-tool 163 | run: | 164 | ./update_libchdb.sh 165 | dotnet tool install --add-source ./nupkg --global chdb-tool 166 | which chdb 167 | cp libchdb.so /home/runner/.dotnet/tools/ 168 | chdb --help 169 | chdb "select version()" PrettyCompact 170 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from `dotnet new gitignore` 5 | 6 | libchdb.tar.gz 7 | chdb.h 8 | src/chdb/libchdb.so 9 | 10 | # dotenv files 11 | .env 12 | 13 | # User-specific files 14 | *.rsuser 15 | *.suo 16 | *.user 17 | *.userosscache 18 | *.sln.docstates 19 | 20 | # User-specific files (MonoDevelop/Xamarin Studio) 21 | *.userprefs 22 | 23 | # Mono auto generated files 24 | mono_crash.* 25 | 26 | # Build results 27 | [Dd]ebug/ 28 | [Dd]ebugPublic/ 29 | [Rr]elease/ 30 | [Rr]eleases/ 31 | x64/ 32 | x86/ 33 | [Ww][Ii][Nn]32/ 34 | [Aa][Rr][Mm]/ 35 | [Aa][Rr][Mm]64/ 36 | bld/ 37 | [Bb]in/ 38 | [Oo]bj/ 39 | [Ll]og/ 40 | [Ll]ogs/ 41 | 42 | # Visual Studio 2015/2017 cache/options directory 43 | .vs/ 44 | # Uncomment if you have tasks that create the project's static files in wwwroot 45 | #wwwroot/ 46 | 47 | # Visual Studio 2017 auto generated files 48 | Generated\ Files/ 49 | 50 | # MSTest test Results 51 | [Tt]est[Rr]esult*/ 52 | [Bb]uild[Ll]og.* 53 | 54 | # NUnit 55 | *.VisualState.xml 56 | TestResult.xml 57 | nunit-*.xml 58 | 59 | # Build Results of an ATL Project 60 | [Dd]ebugPS/ 61 | [Rr]eleasePS/ 62 | dlldata.c 63 | 64 | # Benchmark Results 65 | BenchmarkDotNet.Artifacts/ 66 | 67 | # .NET 68 | project.lock.json 69 | project.fragment.lock.json 70 | artifacts/ 71 | 72 | # Tye 73 | .tye/ 74 | 75 | # ASP.NET Scaffolding 76 | ScaffoldingReadMe.txt 77 | 78 | # StyleCop 79 | StyleCopReport.xml 80 | 81 | # Files built by Visual Studio 82 | *_i.c 83 | *_p.c 84 | *_h.h 85 | *.ilk 86 | *.meta 87 | *.obj 88 | *.iobj 89 | *.pch 90 | *.pdb 91 | *.ipdb 92 | *.pgc 93 | *.pgd 94 | *.rsp 95 | *.sbr 96 | *.tlb 97 | *.tli 98 | *.tlh 99 | *.tmp 100 | *.tmp_proj 101 | *_wpftmp.csproj 102 | *.log 103 | *.tlog 104 | *.vspscc 105 | *.vssscc 106 | .builds 107 | *.pidb 108 | *.svclog 109 | *.scc 110 | 111 | # Chutzpah Test files 112 | _Chutzpah* 113 | 114 | # Visual C++ cache files 115 | ipch/ 116 | *.aps 117 | *.ncb 118 | *.opendb 119 | *.opensdf 120 | *.sdf 121 | *.cachefile 122 | *.VC.db 123 | *.VC.VC.opendb 124 | 125 | # Visual Studio profiler 126 | *.psess 127 | *.vsp 128 | *.vspx 129 | *.sap 130 | 131 | # Visual Studio Trace Files 132 | *.e2e 133 | 134 | # TFS 2012 Local Workspace 135 | $tf/ 136 | 137 | # Guidance Automation Toolkit 138 | *.gpState 139 | 140 | # ReSharper is a .NET coding add-in 141 | _ReSharper*/ 142 | *.[Rr]e[Ss]harper 143 | *.DotSettings.user 144 | 145 | # TeamCity is a build add-in 146 | _TeamCity* 147 | 148 | # DotCover is a Code Coverage Tool 149 | *.dotCover 150 | 151 | # AxoCover is a Code Coverage Tool 152 | .axoCover/* 153 | !.axoCover/settings.json 154 | 155 | # Coverlet is a free, cross platform Code Coverage Tool 156 | coverage*.json 157 | coverage*.xml 158 | coverage*.info 159 | 160 | # Visual Studio code coverage results 161 | *.coverage 162 | *.coveragexml 163 | 164 | # NCrunch 165 | _NCrunch_* 166 | .*crunch*.local.xml 167 | nCrunchTemp_* 168 | 169 | # MightyMoose 170 | *.mm.* 171 | AutoTest.Net/ 172 | 173 | # Web workbench (sass) 174 | .sass-cache/ 175 | 176 | # Installshield output folder 177 | [Ee]xpress/ 178 | 179 | # DocProject is a documentation generator add-in 180 | DocProject/buildhelp/ 181 | DocProject/Help/*.HxT 182 | DocProject/Help/*.HxC 183 | DocProject/Help/*.hhc 184 | DocProject/Help/*.hhk 185 | DocProject/Help/*.hhp 186 | DocProject/Help/Html2 187 | DocProject/Help/html 188 | 189 | # Click-Once directory 190 | publish/ 191 | 192 | # Publish Web Output 193 | *.[Pp]ublish.xml 194 | *.azurePubxml 195 | # Note: Comment the next line if you want to checkin your web deploy settings, 196 | # but database connection strings (with potential passwords) will be unencrypted 197 | *.pubxml 198 | *.publishproj 199 | 200 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 201 | # checkin your Azure Web App publish settings, but sensitive information contained 202 | # in these scripts will be unencrypted 203 | PublishScripts/ 204 | 205 | # NuGet Packages 206 | *.nupkg 207 | # NuGet Symbol Packages 208 | *.snupkg 209 | # The packages folder can be ignored because of Package Restore 210 | **/[Pp]ackages/* 211 | # except build/, which is used as an MSBuild target. 212 | !**/[Pp]ackages/build/ 213 | # Uncomment if necessary however generally it will be regenerated when needed 214 | #!**/[Pp]ackages/repositories.config 215 | # NuGet v3's project.json files produces more ignorable files 216 | *.nuget.props 217 | *.nuget.targets 218 | 219 | # Microsoft Azure Build Output 220 | csx/ 221 | *.build.csdef 222 | 223 | # Microsoft Azure Emulator 224 | ecf/ 225 | rcf/ 226 | 227 | # Windows Store app package directories and files 228 | AppPackages/ 229 | BundleArtifacts/ 230 | Package.StoreAssociation.xml 231 | _pkginfo.txt 232 | *.appx 233 | *.appxbundle 234 | *.appxupload 235 | 236 | # Visual Studio cache files 237 | # files ending in .cache can be ignored 238 | *.[Cc]ache 239 | # but keep track of directories ending in .cache 240 | !?*.[Cc]ache/ 241 | 242 | # Others 243 | ClientBin/ 244 | ~$* 245 | *~ 246 | *.dbmdl 247 | *.dbproj.schemaview 248 | *.jfm 249 | *.pfx 250 | *.publishsettings 251 | orleans.codegen.cs 252 | 253 | # Including strong name files can present a security risk 254 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 255 | #*.snk 256 | 257 | # Since there are multiple workflows, uncomment next line to ignore bower_components 258 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 259 | #bower_components/ 260 | 261 | # RIA/Silverlight projects 262 | Generated_Code/ 263 | 264 | # Backup & report files from converting an old project file 265 | # to a newer Visual Studio version. Backup files are not needed, 266 | # because we have git ;-) 267 | _UpgradeReport_Files/ 268 | Backup*/ 269 | UpgradeLog*.XML 270 | UpgradeLog*.htm 271 | ServiceFabricBackup/ 272 | *.rptproj.bak 273 | 274 | # SQL Server files 275 | *.mdf 276 | *.ldf 277 | *.ndf 278 | 279 | # Business Intelligence projects 280 | *.rdl.data 281 | *.bim.layout 282 | *.bim_*.settings 283 | *.rptproj.rsuser 284 | *- [Bb]ackup.rdl 285 | *- [Bb]ackup ([0-9]).rdl 286 | *- [Bb]ackup ([0-9][0-9]).rdl 287 | 288 | # Microsoft Fakes 289 | FakesAssemblies/ 290 | 291 | # GhostDoc plugin setting file 292 | *.GhostDoc.xml 293 | 294 | # Node.js Tools for Visual Studio 295 | .ntvs_analysis.dat 296 | node_modules/ 297 | 298 | # Visual Studio 6 build log 299 | *.plg 300 | 301 | # Visual Studio 6 workspace options file 302 | *.opt 303 | 304 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 305 | *.vbw 306 | 307 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 308 | *.vbp 309 | 310 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 311 | *.dsw 312 | *.dsp 313 | 314 | # Visual Studio 6 technical files 315 | *.ncb 316 | *.aps 317 | 318 | # Visual Studio LightSwitch build output 319 | **/*.HTMLClient/GeneratedArtifacts 320 | **/*.DesktopClient/GeneratedArtifacts 321 | **/*.DesktopClient/ModelManifest.xml 322 | **/*.Server/GeneratedArtifacts 323 | **/*.Server/ModelManifest.xml 324 | _Pvt_Extensions 325 | 326 | # Paket dependency manager 327 | .paket/paket.exe 328 | paket-files/ 329 | 330 | # FAKE - F# Make 331 | .fake/ 332 | 333 | # CodeRush personal settings 334 | .cr/personal 335 | 336 | # Python Tools for Visual Studio (PTVS) 337 | __pycache__/ 338 | *.pyc 339 | 340 | # Cake - Uncomment if you are using it 341 | # tools/** 342 | # !tools/packages.config 343 | 344 | # Tabs Studio 345 | *.tss 346 | 347 | # Telerik's JustMock configuration file 348 | *.jmconfig 349 | 350 | # BizTalk build output 351 | *.btp.cs 352 | *.btm.cs 353 | *.odx.cs 354 | *.xsd.cs 355 | 356 | # OpenCover UI analysis results 357 | OpenCover/ 358 | 359 | # Azure Stream Analytics local run output 360 | ASALocalRun/ 361 | 362 | # MSBuild Binary and Structured Log 363 | *.binlog 364 | 365 | # NVidia Nsight GPU debugger configuration file 366 | *.nvuser 367 | 368 | # MFractors (Xamarin productivity tool) working folder 369 | .mfractor/ 370 | 371 | # Local History for Visual Studio 372 | .localhistory/ 373 | 374 | # Visual Studio History (VSHistory) files 375 | .vshistory/ 376 | 377 | # BeatPulse healthcheck temp database 378 | healthchecksdb 379 | 380 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 381 | MigrationBackup/ 382 | 383 | # Ionide (cross platform F# VS Code tools) working folder 384 | .ionide/ 385 | 386 | # Fody - auto-generated XML schema 387 | FodyWeavers.xsd 388 | 389 | # VS Code files for those working on multiple tools 390 | .vscode/* 391 | !.vscode/settings.json 392 | !.vscode/tasks.json 393 | !.vscode/launch.json 394 | !.vscode/extensions.json 395 | *.code-workspace 396 | 397 | # Local History for Visual Studio Code 398 | .history/ 399 | 400 | # Windows Installer files from build outputs 401 | *.cab 402 | *.msi 403 | *.msix 404 | *.msm 405 | *.msp 406 | 407 | # JetBrains Rider 408 | *.sln.iml 409 | .idea 410 | 411 | ## 412 | ## Visual studio for Mac 413 | ## 414 | 415 | 416 | # globs 417 | Makefile.in 418 | *.userprefs 419 | *.usertasks 420 | config.make 421 | config.status 422 | aclocal.m4 423 | install-sh 424 | autom4te.cache/ 425 | *.tar.gz 426 | tarballs/ 427 | test-results/ 428 | 429 | # Mac bundle stuff 430 | *.dmg 431 | *.app 432 | 433 | # content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 434 | # General 435 | .DS_Store 436 | .AppleDouble 437 | .LSOverride 438 | 439 | # Icon must end with two \r 440 | Icon 441 | 442 | 443 | # Thumbnails 444 | ._* 445 | 446 | # Files that might appear in the root of a volume 447 | .DocumentRevisions-V100 448 | .fseventsd 449 | .Spotlight-V100 450 | .TemporaryItems 451 | .Trashes 452 | .VolumeIcon.icns 453 | .com.apple.timemachine.donotpresent 454 | 455 | # Directories potentially created on remote AFP share 456 | .AppleDB 457 | .AppleDesktop 458 | Network Trash Folder 459 | Temporary Items 460 | .apdisk 461 | 462 | # content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore 463 | # Windows thumbnail cache files 464 | Thumbs.db 465 | ehthumbs.db 466 | ehthumbs_vista.db 467 | 468 | # Dump file 469 | *.stackdump 470 | 471 | # Folder config file 472 | [Dd]esktop.ini 473 | 474 | # Recycle Bin used on file shares 475 | $RECYCLE.BIN/ 476 | 477 | # Windows Installer files 478 | *.cab 479 | *.msi 480 | *.msix 481 | *.msm 482 | *.msp 483 | 484 | # Windows shortcuts 485 | *.lnk 486 | 487 | # Vim temporary swap files 488 | *.swp 489 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | linux-x64;osx-x64 4 | enable 5 | enable 6 | latest 7 | ChDb 8 | $(NoWarn);CS1591 9 | 10 | 11 | 12 | True 13 | true 14 | ../../nupkg 15 | 0.0.3.0$(GITHUB_RUN_NUMBER) 16 | true 17 | $(Version).$(BuildNumber) 18 | vilinski 19 | Apache-2.0 20 | chdb.png 21 | clickhouse;chdb 22 | README.md 23 | https://github.com/vilinski/chdb 24 | https://github.com/chdb-io/chdb-dotnet 25 | git 26 | Create 27 | 28 | 29 | 30 | true 31 | true 32 | true 33 | true 34 | true 35 | true 36 | true 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # chdb 2 | 3 | A .NET Core binding for [chdb](https://doc.chdb.io) library. 4 | 5 | ![GitHub License](https://img.shields.io/github/license/chdb-io/chdb-dotnet) 6 | ![example workflow](https://github.com/chdb-io/chdb-dotnet/actions/workflows/dotnet.yml/badge.svg) 7 | ![NuGet Version](https://img.shields.io/nuget/vpre/chdb) 8 | ![NuGet Downloads](https://img.shields.io/nuget/dt/chdb) 9 | 10 | ### Architecture 11 | 12 |
13 | 14 |
15 | 16 | ### Usage 17 | 18 | Running on platforms: linux, osx, windows, and architectures: x64, arm64. 19 | 20 | >Note for windows users - there is no windows bild in sight, but you can still use it in WSL. 21 | 22 | Currently the librairy is too large to be packed into a nuget package, so you need to install it manually. Use the [update_libchdb.sh](update_libchdb.sh) script to download the library for your platform and architecture. 23 | 24 | ```bash 25 | # download the latest version of the library - it takes a version as an optional argument 26 | ./update_libchdb.sh 27 | # install the package to your project 28 | dotnet add package chdb 29 | ``` 30 | 31 | Also place the library in appropriate folder, and add following to your csproj file: 32 | 33 | ```xml 34 | 35 | 36 | PreserveNewest 37 | 38 | 39 | ``` 40 | 41 | Then you can use it in your code like this: 42 | 43 | ```csharp 44 | using ChDb; 45 | 46 | var result = ChDb.Query("select version()"); 47 | Console.WriteLine(result.Text); 48 | // 23.10.1.1 49 | var s = new Session(); 50 | var result = s.Query("select * from system.formats where is_output = 1", "PrettyCompact"); 51 | // ┌─name───────────────────────────────────────┬─is_input─┬─is_output─┬─supports_parallel_parsing─┬─supports_parallel_formatting─┐ 52 | // │ Prometheus │ 0 │ 1 │ 0 │ 0 │ 53 | // │ PostgreSQLWire │ 0 │ 1 │ 0 │ 0 │ 54 | // │ MySQLWire │ 0 │ 1 │ 0 │ 0 │ 55 | // │ JSONEachRowWithProgress │ 0 │ 1 │ 0 │ 0 │ 56 | // │ ODBCDriver2 │ 0 │ 1 │ 0 │ 0 │ 57 | // ... 58 | var result = s.Query("DESCRIBE s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/house_parquet/house_0.parquet')"); 59 | Console.WriteLine(result.Text); 60 | ``` 61 | 62 | or use it right in F# interactive with `dotnet fsi`: 63 | 64 | ```fsharp 65 | #r "nuget: chdb" 66 | 67 | open ChDb 68 | 69 | // print out result in the PrettyCompact format by default 70 | let result = ChDb.Query "select version()" 71 | printfn "%s" result.Text 72 | // or save result to a text or binary file in any supported format 73 | let result = ChDb.Query("select * from system.formats where is_output = 1", "CSVWithNames") 74 | System.IO.File.WriteAllBytes("supported_formats.csv", result.Buf) 75 | ``` 76 | 77 | ## chdb-tool 78 | 79 | ![NuGet Version](https://img.shields.io/nuget/vpre/chdb-tool) 80 | ![NuGet Downloads](https://img.shields.io/nuget/dt/chdb-tool) 81 | 82 | This is a dotnet tool, running [chdb](https://doc.chdb.io) library. 83 | Probably you better served using the clickhouse client and run `clickhouse local`, but maybe it is more useful in some cases. 84 | 85 | ### Installation 86 | 87 | Requires .NET SDK 6.0 or later. 88 | 89 | ```bash 90 | dotnet tool install --global chdb-tool 91 | ``` 92 | 93 | OS supported: linux, osx 94 | ARCH supported: x64, arm64 95 | 96 | ### Usage 97 | 98 | Try any of this commands lines to see which output you get. 99 | 100 | ```bash 101 | chdb 102 | chdb --version 103 | chdb --help 104 | chdb "select version()" 105 | chdb "select * from system.formats where is_output = 1" PrettyCompact 106 | ``` 107 | 108 | # Build 109 | 110 | ```bash 111 | ./update_libchdb.sh [v2.0.4] 112 | cp libchdb.so src/chdb/ 113 | dotnet build -c Release 114 | dotnet test -c Release 115 | dotnet pack -c Release 116 | dotnet nuget add source ./nupkg --name chdb 117 | dotnet tool update -g chdb-tool 118 | chdb --version 119 | ``` 120 | 121 | ## Authors 122 | 123 | * [Andreas Vilinski](https://github.com/vilinski) 124 | * [Auxten](https://github.com/auxten) 125 | -------------------------------------------------------------------------------- /chdb-dotnet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chdb-io/chdb-dotnet/db6a04919a737a6f00d5cfa8154c23272897edc9/chdb-dotnet.png -------------------------------------------------------------------------------- /chdb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chdb-io/chdb-dotnet/db6a04919a737a6f00d5cfa8154c23272897edc9/chdb.png -------------------------------------------------------------------------------- /chdb.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.0.31903.59 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{53AE4A72-327B-44A3-BFAF-DF227D4D848A}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "chdb", "src\chdb\chdb.csproj", "{3B3A43FC-6DD0-4285-857C-271D19099613}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "chdb-tool", "src\chdb-tool\chdb-tool.csproj", "{78D934D4-0467-410A-83A7-AC9FF23C1E79}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{F34DFA50-9A9B-406A-8535-D705F29730F3}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "test", "test\ChDbTest\test.csproj", "{458995B1-8DB5-40AC-9703-1049CA8A534B}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(SolutionProperties) = preSolution 22 | HideSolutionNode = FALSE 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {3B3A43FC-6DD0-4285-857C-271D19099613}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {3B3A43FC-6DD0-4285-857C-271D19099613}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {3B3A43FC-6DD0-4285-857C-271D19099613}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {3B3A43FC-6DD0-4285-857C-271D19099613}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {78D934D4-0467-410A-83A7-AC9FF23C1E79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {78D934D4-0467-410A-83A7-AC9FF23C1E79}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {78D934D4-0467-410A-83A7-AC9FF23C1E79}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {78D934D4-0467-410A-83A7-AC9FF23C1E79}.Release|Any CPU.Build.0 = Release|Any CPU 33 | {458995B1-8DB5-40AC-9703-1049CA8A534B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 34 | {458995B1-8DB5-40AC-9703-1049CA8A534B}.Debug|Any CPU.Build.0 = Debug|Any CPU 35 | {458995B1-8DB5-40AC-9703-1049CA8A534B}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {458995B1-8DB5-40AC-9703-1049CA8A534B}.Release|Any CPU.Build.0 = Release|Any CPU 37 | EndGlobalSection 38 | GlobalSection(NestedProjects) = preSolution 39 | {3B3A43FC-6DD0-4285-857C-271D19099613} = {53AE4A72-327B-44A3-BFAF-DF227D4D848A} 40 | {78D934D4-0467-410A-83A7-AC9FF23C1E79} = {53AE4A72-327B-44A3-BFAF-DF227D4D848A} 41 | {458995B1-8DB5-40AC-9703-1049CA8A534B} = {F34DFA50-9A9B-406A-8535-D705F29730F3} 42 | EndGlobalSection 43 | EndGlobal 44 | -------------------------------------------------------------------------------- /src/chdb-meta/chdb-meta.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | chdb 5 | chdb 6 | chdb native bindings for dotnet core 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/chdb-tool/Program.cs: -------------------------------------------------------------------------------- 1 | // See https://aka.ms/new-console-template for more information 2 | 3 | using System.Reflection; 4 | 5 | void PrintVersion() 6 | { 7 | var versionString = Assembly.GetEntryAssembly()? 8 | .GetCustomAttribute()? 9 | .InformationalVersion ?? "unknown"; 10 | Console.WriteLine($"chdb-tool v{versionString}"); 11 | } 12 | 13 | void PrintHelp() 14 | { 15 | PrintVersion(); 16 | Console.WriteLine("-------------"); 17 | Console.WriteLine("\nUsage:"); 18 | Console.WriteLine(" chdb-tool "); 19 | } 20 | 21 | if (args.Length == 0 || args[0] == "--help" || args[0] == "-h") 22 | { 23 | PrintHelp(); 24 | } 25 | else if (args[0] == "--version" || args[0] == "-v") 26 | { 27 | PrintVersion(); 28 | } 29 | else 30 | try 31 | { 32 | var result = ChDb.ChDb.Query(args[0], args.Length > 1 && !args[1].StartsWith('-') ? args[1] : "PrettyCompact"); 33 | if (result == null) 34 | return; // TODO behavior changed in 1.2.1 35 | Console.WriteLine(result.Text); 36 | if (!args.Contains("--quiet") && !args.Contains("-q")) 37 | { 38 | Console.WriteLine($"Elapsed: {result.Elapsed} s, read {result.RowsRead} rows, {result.BytesRead} bytes" + 39 | $", {result.RowsRead / result.Elapsed.TotalSeconds:F0} rows/s, {result.BytesRead / result.Elapsed.TotalSeconds:F0} bytes/s"); 40 | if (!string.IsNullOrWhiteSpace(result.ErrorMessage)) 41 | Console.Error.WriteLine("Error message: " + result.ErrorMessage); 42 | } 43 | } 44 | catch (ArgumentException e) 45 | { 46 | Console.Error.WriteLine(e.Message); 47 | Environment.Exit(1); 48 | } 49 | -------------------------------------------------------------------------------- /src/chdb-tool/chdb-tool.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | net6.0;net8.0 15 | Exe 16 | true 17 | chdb 18 | chdb-tool 19 | 23 | chdb tool 24 | clickhouse local cli as a dotnet tool 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/chdb/ChDb.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | using System.Runtime.InteropServices; 3 | using System.Security; 4 | 5 | namespace ChDb; 6 | 7 | internal static class NativeMethods 8 | { 9 | private const string __DllName = "libchdb.so"; 10 | 11 | [DllImport(__DllName, EntryPoint = "query_stable_v2", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] 12 | internal static extern IntPtr query_stable_v2(int argc, string[] argv); 13 | 14 | [DllImport(__DllName, EntryPoint = "free_result_v2", CallingConvention = CallingConvention.Cdecl, ExactSpelling = true)] 15 | internal static extern void free_result_v2(IntPtr result); 16 | } 17 | 18 | /// 19 | /// Entry point for stateless chdb queries. 20 | /// 21 | public static class ChDb 22 | { 23 | /// 24 | /// Execute a stateless query and return the result. 25 | /// 26 | /// SQL query 27 | /// Optional output format from supported by clickhouse. Default is TabSeparated. 28 | /// Query result 29 | /// 30 | /// Stateless queries are useful for simple queries that do not require a session. 31 | /// Use if you need to create databases or tables. 32 | /// Set to a non-temporary directory to keep the data between sessions. 33 | /// 34 | public static LocalResult? Query(string query, string? format = null) 35 | { 36 | if (query is null) 37 | throw new ArgumentNullException(nameof(query)); 38 | var argv = new[] { 39 | "clickhouse", 40 | "--multiquery", 41 | $"--query={query}", 42 | $"--output-format={format ?? "TabSeparated"}" 43 | }; 44 | return Execute(argv); 45 | } 46 | 47 | private static string? LookUpArg(string[] argv, string key) 48 | { 49 | foreach (var arg in argv) 50 | { 51 | var prefix = $"--{key}="; 52 | if (arg.StartsWith(prefix)) 53 | return arg.Substring(prefix.Length); 54 | } 55 | return null; 56 | } 57 | 58 | [SuppressUnmanagedCodeSecurity] 59 | [SecurityCritical] 60 | internal static LocalResult? Execute(string[] argv) 61 | { 62 | try 63 | { 64 | var ptr = NativeMethods.query_stable_v2(argv.Length, argv); 65 | var res = LocalResult.FromPtr(ptr); 66 | NativeMethods.free_result_v2(ptr); 67 | // Marshal.FreeHGlobal(ptr); 68 | return res; 69 | } 70 | catch (RuntimeWrappedException e) 71 | { 72 | if (e.WrappedException is string s) 73 | throw new ArgumentException($"Unmanaged string error {s}"); 74 | else 75 | throw new ArgumentException($"Unmanaged unknown error {e.WrappedException}"); 76 | } 77 | catch (Exception e) 78 | { 79 | throw new Exception("Managed error", e); 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /src/chdb/LocalResult.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | namespace ChDb; 4 | 5 | /// 6 | /// The query result. 7 | /// 8 | public record LocalResult 9 | { 10 | public byte[]? Buf { get; } 11 | public string? ErrorMessage { get; } 12 | /// 13 | /// By text formats contains a result text. 14 | /// 15 | public string? Text => Buf == null ? null : System.Text.Encoding.UTF8.GetString(Buf); 16 | public ulong RowsRead { get; } 17 | public ulong BytesRead { get; } 18 | public TimeSpan Elapsed { get; } 19 | 20 | /// Result buffer. 21 | /// Error message if occured. 22 | /// Number of rows read 23 | /// Number of bytes read 24 | /// Query time elapsed, in seconds. 25 | public LocalResult(byte[]? Buf, string? ErrorMessage, ulong RowsRead, ulong BytesRead, TimeSpan Elapsed) 26 | { 27 | this.Buf = Buf; 28 | this.ErrorMessage = ErrorMessage; 29 | this.RowsRead = RowsRead; 30 | this.BytesRead = BytesRead; 31 | this.Elapsed = Elapsed; 32 | } 33 | 34 | internal static LocalResult? FromPtr(nint ptr) 35 | { 36 | if (ptr == IntPtr.Zero) 37 | return null; 38 | var h = Marshal.PtrToStructure(ptr); 39 | if (h == null) 40 | return null; 41 | 42 | var errorMessage = h.error_message == IntPtr.Zero ? null : MarshalPtrToStringUTF8(h.error_message); 43 | if (errorMessage != null) 44 | return new LocalResult(null, errorMessage, 0, 0, TimeSpan.Zero); 45 | 46 | var elapsed = TimeSpan.FromSeconds(h.elapsed); 47 | 48 | var buf = h.buf == IntPtr.Zero ? null : new byte[h.len]; 49 | if (buf != null) 50 | Marshal.Copy(h.buf, buf, 0, h.len); 51 | return new LocalResult(buf, errorMessage, h.rows_read, h.bytes_read, elapsed); 52 | } 53 | 54 | private static string MarshalPtrToStringUTF8(nint ptr) 55 | { 56 | unsafe 57 | { 58 | var str = (byte*)ptr; 59 | var length = 0; 60 | for (var i = str; *i != 0; i++, length++) ; 61 | var clrString = System.Text.Encoding.UTF8.GetString(str, length); 62 | return clrString; 63 | } 64 | } 65 | 66 | [StructLayout(LayoutKind.Sequential)] 67 | internal class Handle 68 | { 69 | internal nint buf; 70 | internal int len; 71 | internal nint _vec; // std::vector *, for freeing 72 | internal double elapsed; 73 | internal ulong rows_read; 74 | internal ulong bytes_read; 75 | internal nint error_message; 76 | 77 | public override string ToString() => $"Handle{{\n\tbuf={buf},\n\tlen={len},\n\t_vec={_vec},\n\telapsed={elapsed},\n\trows_read={rows_read},\n\tbytes_read={bytes_read},\n\terror_message={error_message}}}"; 78 | } 79 | } -------------------------------------------------------------------------------- /src/chdb/Session.cs: -------------------------------------------------------------------------------- 1 | namespace ChDb; 2 | 3 | public record Session : IDisposable 4 | { 5 | /// 6 | /// Output format for queries if not explicitely specified. Default is TabSeparated 7 | /// 8 | public string? Format { get; set; } 9 | /// 10 | /// Path to the ClickHouse data directory. If not set, a temporary directory will be used. 11 | /// 12 | public string? DataPath { get; set; } = Path.Combine(Path.GetTempPath(), "chdb_"); 13 | /// 14 | /// Query Log Level. 15 | /// 16 | public string? LogLevel { get; set; } 17 | /// 18 | /// Whether to delete the data directory on dispose. Default is true. 19 | /// 20 | public bool IsTemp { get; set; } = true; 21 | 22 | public void Dispose() 23 | { 24 | if (IsTemp && DataPath?.EndsWith("chdb_") == true && Directory.Exists(DataPath)) 25 | Directory.Delete(DataPath, true); 26 | } 27 | 28 | /// 29 | /// Execute a query and return the result. 30 | /// 31 | /// SQL query 32 | /// Output format, optional. 33 | /// Query result 34 | public LocalResult? Query(string query, string? format = null) 35 | { 36 | if (IsTemp && DataPath is null) 37 | { 38 | DataPath = Path.Combine(Path.GetTempPath(), "chdb_"); 39 | } 40 | 41 | var argv = new[] { 42 | "clickhouse", 43 | "--multiquery", 44 | $"--query={query}", 45 | $"--output-format={format ?? Format ?? "TabSeparated"}", //$"--path={DataPath}", 46 | $"--path={DataPath}", 47 | // $"--user_scripts_path={UdfPath}", $"--user_defined_executable_functions_config={UdfPath}/*.xml", 48 | $"--log-level={LogLevel ?? "trace"}", 49 | }; 50 | return ChDb.Execute(argv); 51 | } 52 | } -------------------------------------------------------------------------------- /src/chdb/chdb.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | tests 5 | netstandard2.1 6 | 10 | chdb 11 | chdb 12 | chdb native bindings for dotnet core 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/ChDbTest/ChDbTest.cs: -------------------------------------------------------------------------------- 1 | namespace ChDb; 2 | 3 | [TestClass] 4 | public class ChDbTest 5 | { 6 | [TestMethod] 7 | public void QueryVersionTest() 8 | { 9 | var result = ChDb.Query("select version()"); 10 | Assert.IsNotNull(result); 11 | Assert.AreEqual(1UL, result.RowsRead); 12 | Assert.AreEqual(50UL, result.BytesRead); 13 | Assert.AreEqual("24.5.1.1\n", result.Text); 14 | Assert.IsNull(result.ErrorMessage); 15 | Assert.AreNotEqual(TimeSpan.Zero, result.Elapsed); 16 | } 17 | 18 | [TestMethod] 19 | public void QueryErrorTest() 20 | { 21 | Assert.ThrowsException(() => ChDb.Query(null!)); 22 | // TODO behavior changed in 1.2.1 23 | var r1 = ChDb.Query("wrong_query"); 24 | Assert.IsNotNull(r1); 25 | Assert.IsNull(r1.Text); 26 | Assert.IsNotNull(r1.ErrorMessage); 27 | 28 | var r2 = ChDb.Query("wrong_query", "PrettyCompact"); 29 | Assert.IsNotNull(r2); 30 | Assert.IsNull(r2.Text); 31 | Assert.IsNotNull(r2.ErrorMessage); 32 | 33 | var r3 = ChDb.Query("select version()", "wrong_format"); 34 | Assert.IsNotNull(r3); 35 | Assert.IsNull(r3.Text); 36 | StringAssert.Contains(r3.ErrorMessage, "Unknown output format"); 37 | } 38 | 39 | [TestMethod] 40 | public void NoDataTest() 41 | { 42 | var result = ChDb.Query("create table x(a UInt8, b UInt8, c UInt8) Engine=Memory"); 43 | Assert.IsNotNull(result); 44 | Assert.AreEqual(0UL, result.RowsRead); 45 | Assert.AreEqual(0UL, result.BytesRead); 46 | Assert.IsNull(result.Text); 47 | Assert.IsNull(result.ErrorMessage); 48 | Assert.AreNotEqual(TimeSpan.Zero, result.Elapsed); 49 | Assert.IsTrue(0.1 > result.Elapsed.TotalSeconds); 50 | } 51 | 52 | [TestMethod] 53 | public void EmptyResultTest() 54 | { 55 | var result = ChDb.Query("show tables"); 56 | Assert.IsNotNull(result); 57 | Assert.AreEqual(0UL, result.RowsRead); 58 | Assert.AreEqual(0UL, result.BytesRead); 59 | Assert.AreEqual("", result.Text); 60 | Assert.IsNull(result.ErrorMessage); 61 | Assert.AreNotEqual(TimeSpan.Zero, result.Elapsed); 62 | Assert.IsTrue(0.1 > result.Elapsed.TotalSeconds); 63 | } 64 | 65 | [TestMethod] 66 | public void RowNumberTest() 67 | { 68 | var result = ChDb.Query("SELECT * FROM numbers(10)"); 69 | Assert.IsNotNull(result); 70 | Assert.AreEqual(10UL, result.RowsRead); 71 | } 72 | 73 | [TestMethod] 74 | public void FormatTest() 75 | { 76 | Assert.AreEqual("1\t2\t3\n", ChDb.Query("SELECT 1 as a, 2 b, 3 c")!.Text); 77 | Assert.AreEqual("1,2,3\n", ChDb.Query("SELECT 1 as a, 2 b, 3 c", "CSV")!.Text); 78 | Assert.AreEqual("\"a\",\"b\",\"c\"\n1,2,3\n", ChDb.Query("SELECT 1 as a, 2 b, 3 c", "CSVWithNames")!.Text); 79 | StringAssert.Contains(ChDb.Query("SELECT 1 as a, 2 b, 3 c", "CSVWithNamesAndTypes")!.Text, "UInt8"); 80 | } 81 | 82 | [TestMethod] 83 | public void InMemoryTest() 84 | { 85 | var sql = 86 | """ 87 | create table test (a UInt8, b UInt8, c UInt8) Engine=Memory; 88 | insert into test values (1, 2, 3); 89 | select * from test; show tables; 90 | drop table test;show tables 91 | """; 92 | var result = ChDb.Query(sql); 93 | Assert.IsNotNull(result); 94 | Assert.AreEqual("", result.Text); 95 | Assert.AreEqual(null, result.ErrorMessage); 96 | } 97 | 98 | [TestMethod] 99 | public void S3ParquetTest() 100 | { 101 | var result = ChDb.Query("DESCRIBE s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/house_parquet/house_0.parquet')"); 102 | Assert.IsNotNull(result); 103 | Assert.IsNull(result.ErrorMessage); 104 | StringAssert.StartsWith(result.Text, "price\tNullable(Int64)"); 105 | } 106 | 107 | [TestMethod] 108 | public void S3CountTest() 109 | { 110 | var result = ChDb.Query( 111 | """ 112 | SELECT count() 113 | FROM s3('https://datasets-documentation.s3.eu-west-3.amazonaws.com/house_parquet/house_0.parquet') 114 | """); 115 | Assert.IsNotNull(result); 116 | Assert.IsNull(result.ErrorMessage); 117 | Assert.IsTrue(int.TryParse(result.Text, out var count)); 118 | Assert.AreEqual(2772030, count); 119 | } 120 | 121 | [TestMethod] 122 | public void CsvTest() 123 | { 124 | var csv = """ 125 | Name, Age, City 126 | John, 25, New York 127 | Alice, 30, London 128 | Bob, 22, Tokyo 129 | Eva, 28, Paris 130 | """; 131 | var dataPath = "/tmp/chdb/data"; 132 | if (Directory.Exists(dataPath)) 133 | Directory.Delete(dataPath, true); 134 | Directory.CreateDirectory(dataPath); 135 | File.WriteAllText(Path.Combine(".", "test.csv"), csv); 136 | using var session = new Session 137 | { 138 | IsTemp = false, 139 | Format = "PrettyCompact", 140 | DataPath = dataPath, 141 | LogLevel = "trace", 142 | }; 143 | var result = session.Query("SELECT * FROM 'test.csv'", "CSVWithNamesAndTypes"); 144 | // Console.WriteLine($"Error message:\n{result?.ErrorMessage}"); 145 | // Console.WriteLine($"Query result:\n{result?.Text}"); 146 | Assert.IsNotNull(result); 147 | Assert.AreEqual(4UL, result.RowsRead); 148 | Assert.AreEqual(155UL, result.BytesRead); 149 | StringAssert.StartsWith(result.Text, 150 | """ 151 | "Name","Age","City" 152 | """); 153 | } 154 | 155 | [TestMethod] 156 | public void SessionTest() 157 | { 158 | using var s = new Session 159 | { 160 | Format = "PrettyCompact", 161 | LogLevel = "trace", 162 | }; 163 | var nr = "xyz"; 164 | 165 | var result = s.Query($"select version()"); 166 | // Console.WriteLine($"Error message:\n{result?.ErrorMessage}"); 167 | // Console.WriteLine($"Query result:\n{result?.Text}"); 168 | Assert.IsNull(s.Query($"select version()")?.ErrorMessage); 169 | 170 | StringAssert.Contains(s.Query($"SHOW DATABASES")?.Text, "default"); 171 | StringAssert.Contains(s.Query($"SELECT currentDatabase()")?.Text, "default"); 172 | Assert.AreEqual("", s.Query($"SHOW TABLES")?.Text); 173 | 174 | var r1 = s.Query($"DROP DATABASE IF EXISTS db_{nr}"); 175 | Assert.IsNotNull(r1); 176 | Assert.IsNull(r1.Text); 177 | Assert.IsNull(r1.ErrorMessage); 178 | 179 | var r2 = s.Query($"CREATE DATABASE IF NOT EXISTS db_{nr} ENGINE = Atomic"); 180 | Assert.IsNotNull(r2); 181 | Assert.IsNull(r2.Text); 182 | Assert.IsNull(r2.ErrorMessage); 183 | 184 | var r3 = s.Query($"CREATE TABLE IF NOT EXISTS db_{nr}.log_table_{nr} (x String, y Int) ENGINE = Log;"); 185 | Assert.IsNotNull(r3); 186 | Assert.IsNull(r3.Text); 187 | Assert.IsNull(r3.ErrorMessage); 188 | 189 | var r4 = s.Query($"INSERT INTO db_{nr}.log_table_{nr} VALUES ('a', 1), ('b', 3), ('c', 2), ('d', 5);"); 190 | Assert.IsNotNull(r4); 191 | Assert.IsNull(r4.Text); 192 | Assert.IsNull(r4.ErrorMessage); 193 | 194 | var r5 = s.Query($"SELECT * FROM db_{nr}.log_table_{nr}", "TabSeparatedWithNames"); 195 | Assert.IsNotNull(r5); 196 | Assert.AreEqual("x\ty\na\t1\nb\t3\nc\t2\nd\t5\n", r5.Text); 197 | Assert.IsNull(r5.ErrorMessage); 198 | 199 | var r6 = s.Query($"CREATE VIEW db_{nr}.view_{nr} AS SELECT * FROM db_{nr}.log_table_{nr} LIMIT 4;"); 200 | Assert.IsNotNull(r6); 201 | Assert.IsNull(r6.Text); 202 | Assert.IsNull(r6.ErrorMessage); 203 | 204 | var r7 = s.Query($"SELECT * FROM db_{nr}.view_{nr}", "TabSeparatedWithNames"); 205 | Assert.IsNotNull(r7); 206 | Assert.AreEqual("x\ty\na\t1\nb\t3\nc\t2\nd\t5\n", r7.Text); 207 | Assert.IsNull(r7.ErrorMessage); 208 | 209 | s.Query($"DROP DATABASE IF EXISTS db_{nr}"); 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /test/ChDbTest/GlobalUsings.cs: -------------------------------------------------------------------------------- 1 | global using Microsoft.VisualStudio.TestTools.UnitTesting; -------------------------------------------------------------------------------- /test/ChDbTest/test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0;net8.0 5 | false 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /update_libchdb.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Download the correct version based on the platform 4 | case "$(uname -s)" in 5 | Linux) 6 | if [[ $(uname -m) == "aarch64" ]]; then 7 | PLATFORM="linux-aarch64" 8 | else 9 | PLATFORM="linux-x86_64" 10 | fi 11 | ;; 12 | Darwin) 13 | if [[ $(uname -m) == "arm64" ]]; then 14 | PLATFORM="macos-arm64" 15 | else 16 | PLATFORM="macos-x86_64" 17 | fi 18 | ;; 19 | *) 20 | echo "Unsupported platform" 21 | exit 1 22 | ;; 23 | esac 24 | 25 | # Get the newest release version 26 | # LATEST_RELEASE=$(curl --silent "https://api.github.com/repos/chdb-io/chdb/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') 27 | LATEST_RELEASE=v2.0.4 28 | RELEASE=${1:-$LATEST_RELEASE} 29 | 30 | DOWNLOAD_URL="https://github.com/chdb-io/chdb/releases/download/$RELEASE/$PLATFORM-libchdb.tar.gz" 31 | 32 | echo "Downloading $PLATFORM-libchdb.tar.gz from $DOWNLOAD_URL (latest is $LATEST_RELEASE)" 33 | 34 | # Download the file 35 | curl -L -o libchdb.tar.gz "$DOWNLOAD_URL" 36 | 37 | # Untar the file 38 | tar -xzf libchdb.tar.gz 39 | 40 | # Set execute permission for libchdb.so 41 | chmod +x libchdb.so 42 | 43 | # Clean up 44 | rm -f libchdb.tar.gz 45 | --------------------------------------------------------------------------------