Compare commits

..

3 commits

Author SHA1 Message Date
Sal
a9a3548588
update key features 2026-04-13 15:33:17 -04:00
Sal
52cf523f7a
V4.1.1 Release (#182)
* don't allow 0 record count

* add test for #181

* bump version

* add TimeOnly support
2026-04-10 21:46:53 -04:00
Sal
37b603f765
V4.1.0 Release (#175)
* rough duckdb functionality

* add internationalization support (#145)
address #169

* moar localization that i missed

* localize some exceptions

* address random exceptions i found in amplitude

* localize gridview better

* add language toolstrip item

* tweak filter query area width in mainform

* add amplitude user property for ui language

* add bytearrayvalue truncation test

* better localization for custom date format form

* add comments

* reset default designer language to english

* fix button text alignment

* create workflow to automatically generate a translation template.

* tweak workflow

* Auto-generated file update

* add issue template for translations

* remove duplicate resx file causing build failures

* remove solution items

* log exe size after compile

* update workflow

* update build flags

* create 100k rowgroups when exporting data to parquet format

* moar translations

* simplify string formatting

* actually allow cancellation of parquet export

* Auto-generated file update

* localize unhandled exception message

* Auto-generated file update

* trigger build

* moar translations

* Auto-generated file update

* trigger builds

* widen labels a bit more

* Delete src/ParquetViewer/Resources/localization-icon.ico

* moar duckdb implementation

* mostly green tests!

* all tests are green!

* implement custom metadata support for DuckDB

* byte array support for duckdb

* cleanup

* moar cleanup

* this is cleaner

* custom metadata changes

* upgrade to .net 10

* fix sql create script

* add automatic duckdb fallback when opening files

* add more tests for files we support now thanks to duckdb

* better duckdb fallback logic

* capture engine usage in amplitude and separate exceptions for each engine

* improve byte[] compatibility

* improve duckdb engine

* cleanup and more tests

* deserialize column stat values

* fix detailed metadata resolution for parquetnet

* add metadata test

* dotnet format

* create new query editor tool

* better ex handling

* simplify types

* capture analytics

* localize query editor

* theme the query editor

* adjust max window sizes

* fix map type for query editor

* re-implement parquet exports via parquetnet. duckdb exports still needs to be implemented

* gracefully fail when byte[] types are in query result

* fix merge errors

* query editor theme and usability improvements

* Auto-generated file update

* confirmed todo

* remove the concept of unsupported fields (!!)

* fix build

* Auto-generated file update

* adjust translations workflow

* Auto-generated file update

* use correct date wrapper for query editor grid

* Auto-generated file update

* ParquetViewer wouldn't be here today without Parquet.NET but I think it's time to remove this special thanks. I hope this doesn't come across the wrong way <3

* more cleanup

* update build process to net10

* use ready to run and only publish self contained exe's now :(

* add copy/paste context menu to query editor

* better handle huggingface middle-click shortcut

* proper start location

* Auto-generated file update

* lint

* update count label correctly

* remove query editor and make duckdb a selfcontained exe only feature

* cleanup

* add ability to freeze columns #174

* use display index instead of ordinal index

* fix styling reset

* fix bug with frozen columns and quick peek's back functionality

* bump packages

* Auto-generated file update

* comma

* dont use readytorun

* fix bug in field selection dialog column filtering

* Auto-generated file update

* bump version

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-03-20 21:57:08 -04:00
35 changed files with 1054 additions and 2737 deletions

View file

@ -59,7 +59,6 @@
"MainForm.resx","newToolStripMenuItem.Text",,"&New","Yeni",""
"MainForm.resx","openFolderToolStripMenuItem.Text",,"&Open Folder","Klasör Aç",""
"MainForm.resx","openFolderToolStripMenuItem.ToolTipText",,"All parquet files in the folder must have the same schema","Klasördeki tüm parquet dosyaları aynı veri şemasına sahip olmalıdır",""
"MainForm.resx","openQueryEditorToolToolStripMenuItem.Text",,"Query Editor (Beta)","Sorgu Editörü (Beta)",""
"MainForm.resx","openToolStripMenuItem.Text",,"&Open File","Dosya Aç",""
"MainForm.resx","outOfStatusBarLabel.Text",,"Out of:","Toplam:",""
"MainForm.resx","recordsTextStatusBarLabel.Text",,"Results","Sonuç",""
@ -77,19 +76,6 @@
"MetadataViewer.resx","$this.Text",,"Parquet Metadata Viewer","Parquet Metadata Önizleyicisi",""
"MetadataViewer.resx","closeButton.Text",,"Close","Kapat",""
"MetadataViewer.resx","loadingTab.Text",,"Loading...","Yükleniyor...",""
"QueryEditor.resx","$this.Text",,"ParquetViewer - Query Editor (Powered by DuckDB)","ParquetViewer - Sorgu Editörü (DuckDB Desteğiyle)",""
"QueryEditor.resx","copyTextMenuItem.Text",,"Copy","Kopyala",""
"QueryEditor.resx","executeQueryButton.Text",,"Execute","İşle",""
"QueryEditor.resx","pasteTextMenuItem.Text",,"Paste","Yapıştır",""
"QueryEditor.resx","queryExecutionStatusLabel.Text",,"Running:","İşleniyor:",""
"QueryEditor.resx","querySyntaxDocsButton.Text",,"Query Syntax","Sorgu Söz Dizimi",""
"QueryEditor.resx","toolStripStatusLabel1.Text",,"Showing:","Gösterilen:",""
"QueryEditor.resx","toolStripStatusLabel2.Text",,"Results","Sonuç",""
"QueryEditor.resx","zoomPercentageDropDown.Text",,"Query Zoom: 100%","Sorgu Zumu: 100%",""
"QuickPeekForm.resx","$this.Text",,"Quick Peek","Hızlı Önizleme",""
"QuickPeekForm.resx","copyToClipboardToolStripMenuItem.Text",,"Copy to clipboard","Panoya kopyala",""
"QuickPeekForm.resx","saveImageToFileButton.Text",,"Save as PNG","PNG olarak Kaydet",""
"QuickPeekForm.resx","takeMeBackLinkLabel.Text",,"<<< back","<<< geri",""
"Errors.resx","CopyAsWhereTooLargeErrorMessage","Shown when the user right-click's on too many cells and selects the Copy as WHERE... option","The selected data is too large. Please select less cells.","Çok fazla veri seçili. Lütfen daha az hücre seçin.",""
"Errors.resx","CopyAsWhereTooLargeErrorTitle","Shown when the user right-click's on too many cells and selects the Copy as WHERE... option","Copy to clipboard failed","Panoya kopyalama başarısız oldu",""
"Errors.resx","CopyErrorMessageText","Shown in the messagebox for unhandled exceptions to teach users how to copy the error text","(CTRL+C to copy)","(Kopyalamak için CTRL+C)",""
@ -211,6 +197,7 @@ Bu ayarı Yardim → Hakkinda sayfasında da yapabilirsiniz.",""
"Strings.resx","FileExtensionAssociationPromptTitle","Message box title shown when we ask the user if they'd like to associate .parquet files with ParquetViewer","ParquetViewer file association request","ParquetViewer varsayılan uygulama isteği",""
"Strings.resx","FileExtensionAssociationSucceededMessage","Shown when file association succeeds AFTER we ask the user if they'd like to associate ParquetViewer with parquet files","Success! ParquetViewer is now your default application for .parquet files.","Uzantı ilişkilendirmesi başarılı oldu! ParquetViewer .parquet dosyaları için varsayılan uygulamanız olarak ayarlanmıştır.",""
"Strings.resx","FileExtensionAssociationSucceededTitle","Shown when file association succeeds AFTER we ask the user if they'd like to associate ParquetViewer with parquet files","File association succeeded","Uzantı ilişkilendirmesi başarılı",""
"Strings.resx","FrozenColumnText","When the user right-clicks on a column header this is the text shown for freezing the column. Freezing a column makes it so it is always visible no matter how much you scroll horizontally.","Frozen","Dondur",""
"Strings.resx","ImageSavedToDiskMessage","Shown when an image is successfully saved to disk from the quick peek form","Image saved to {0}","Görüntü kaydedildi: {0}",""
"Strings.resx","ImageSavedToDiskTitle","Shown when an image is successfully saved to disk from the quick peek form","Save complete","Kayıt tamamlandı",""
"Strings.resx","IndexingDataLabelText","Text shown while data is being indexed","Indexing","Dizinleniyor",""
@ -282,3 +269,7 @@ Onun yerine sonuçlari {2} dosyasına aktarmak ister misiniz?",""
"Strings.resx","TooManyFieldsErrorFormat","Shown on the Field Selection Dialog when there are too many fields to filter by","Too many fields: {0}","Desteklenmeyen sayıda alan: {0}",""
"Strings.resx","TypeText","Shown in the title bar of quick peek windows for image previews","Type","Format",""
"Strings.resx","UnsupportedFieldCountTextFormat","Shown in the field selection dialog to indicate how many fields are unsupported by ParquetViewer","Unsupported: {0}","Desteklenmeyen: {0}",""
"QuickPeekForm.resx","$this.Text",,"Quick Peek","Hızlı Önizleme",""
"QuickPeekForm.resx","copyToClipboardToolStripMenuItem.Text",,"Copy to clipboard","Panoya kopyala",""
"QuickPeekForm.resx","saveImageToFileButton.Text",,"Save as PNG","PNG olarak Kaydet",""
"QuickPeekForm.resx","takeMeBackLinkLabel.Text",,"<<< back","<<< geri",""

1 File Key Comment EnglishValue TurkishValue NewLanguageValue
59 MainForm.resx newToolStripMenuItem.Text &New Yeni
60 MainForm.resx openFolderToolStripMenuItem.Text &Open Folder Klasör Aç
61 MainForm.resx openFolderToolStripMenuItem.ToolTipText All parquet files in the folder must have the same schema Klasördeki tüm parquet dosyaları aynı veri şemasına sahip olmalıdır
MainForm.resx openQueryEditorToolToolStripMenuItem.Text Query Editor (Beta) Sorgu Editörü (Beta)
62 MainForm.resx openToolStripMenuItem.Text &Open File Dosya Aç
63 MainForm.resx outOfStatusBarLabel.Text Out of: Toplam:
64 MainForm.resx recordsTextStatusBarLabel.Text Results Sonuç
76 MetadataViewer.resx $this.Text Parquet Metadata Viewer Parquet Metadata Önizleyicisi
77 MetadataViewer.resx closeButton.Text Close Kapat
78 MetadataViewer.resx loadingTab.Text Loading... Yükleniyor...
QueryEditor.resx $this.Text ParquetViewer - Query Editor (Powered by DuckDB) ParquetViewer - Sorgu Editörü (DuckDB Desteğiyle)
QueryEditor.resx copyTextMenuItem.Text Copy Kopyala
QueryEditor.resx executeQueryButton.Text Execute İşle
QueryEditor.resx pasteTextMenuItem.Text Paste Yapıştır
QueryEditor.resx queryExecutionStatusLabel.Text Running: İşleniyor:
QueryEditor.resx querySyntaxDocsButton.Text Query Syntax Sorgu Söz Dizimi
QueryEditor.resx toolStripStatusLabel1.Text Showing: Gösterilen:
QueryEditor.resx toolStripStatusLabel2.Text Results Sonuç
QueryEditor.resx zoomPercentageDropDown.Text Query Zoom: 100% Sorgu Zumu: 100%
QuickPeekForm.resx $this.Text Quick Peek Hızlı Önizleme
QuickPeekForm.resx copyToClipboardToolStripMenuItem.Text Copy to clipboard Panoya kopyala
QuickPeekForm.resx saveImageToFileButton.Text Save as PNG PNG olarak Kaydet
QuickPeekForm.resx takeMeBackLinkLabel.Text <<< back <<< geri
79 Errors.resx CopyAsWhereTooLargeErrorMessage Shown when the user right-click's on too many cells and selects the Copy as WHERE... option The selected data is too large. Please select less cells. Çok fazla veri seçili. Lütfen daha az hücre seçin.
80 Errors.resx CopyAsWhereTooLargeErrorTitle Shown when the user right-click's on too many cells and selects the Copy as WHERE... option Copy to clipboard failed Panoya kopyalama başarısız oldu
81 Errors.resx CopyErrorMessageText Shown in the messagebox for unhandled exceptions to teach users how to copy the error text (CTRL+C to copy) (Kopyalamak için CTRL+C)
197
198
199
200
201
202
203
269
270
271
272
273
274
275

View file

@ -20,14 +20,14 @@ jobs:
skip-publish: ${{ steps.check-tag.outputs.exists }}
continue-on-error: true
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
sparse-checkout: |
.github
src
- name: Setup .NET
uses: actions/setup-dotnet@v4.0.1
uses: actions/setup-dotnet@v5
with:
dotnet-version: '8.0.x'
@ -41,7 +41,7 @@ jobs:
run: dotnet test src/ParquetViewer.sln --no-build --logger trx
- name: Test Report
uses: bibipkins/dotnet-test-reporter@v1.4.1
uses: bibipkins/dotnet-test-reporter@v1.6.1
if: github.repository == 'mukunku/ParquetViewer'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
@ -56,7 +56,7 @@ jobs:
release_version: ${{ steps.release-version.outputs.release_version }}
should_publish: ${{ steps.should-publish.outputs.should_publish }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
sparse-checkout: |
src/ParquetViewer/Properties/AssemblyInfo.cs
@ -72,7 +72,7 @@ jobs:
Write-Host "Checking version $versionMatch"
- name: Is there a finalized release already
uses: mukunku/release-exists-action@v1.0.0
uses: mukunku/release-exists-action@v1.1.0
id: check-release
with:
tag: 'v${{ steps.release-version.outputs.release_version }}'
@ -90,7 +90,7 @@ jobs:
PR_NUMBER: ${{ github.event.number }}
VERSION_NUMBER: ${{ needs.checkPublish.outputs.release_version }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
with:
sparse-checkout: |
.github
@ -108,12 +108,10 @@ jobs:
search-text: 'private const string AMPLITUDE_API_KEY = "";'
replacement-text: 'private const string AMPLITUDE_API_KEY = "${{ secrets.AMPLITUDE_API_KEY }}";'
# With DuckDB, the regular release is close to 40MB which defeats the purpose of having this version of the release.
# Starting with v4.0.0 we're switching to only publishing the self-contained version.
#- name: Build & Publish Regular Release
# run: |
# dotnet publish src/ParquetViewer/ParquetViewer.csproj -c Release -f net10.0-windows --nologo -o publish -r win-x64 --no-self-contained
# Get-Item "./publish/ParquetViewer.exe" | Select-Object Name, Length
- name: Build & Publish Regular Release
run: |
dotnet publish src/ParquetViewer/ParquetViewer.csproj -c Release -f net10.0-windows --nologo -o publish -r win-x64 --no-self-contained
Get-Item "./publish/ParquetViewer.exe" | Select-Object Name, Length
- name: Build & Publish SelfContained Release
run: |
@ -122,25 +120,25 @@ jobs:
- name: Prepare executables for upload
run: |
#Move-Item -Path "publish/ParquetViewer.exe" -Destination "./ParquetViewer.exe"
Move-Item -Path "publish_selfcontained/ParquetViewer.exe" -Destination "./ParquetViewer.exe"
Move-Item -Path "publish/ParquetViewer.exe" -Destination "./ParquetViewer.exe"
Move-Item -Path "publish_selfcontained/ParquetViewer.exe" -Destination "./ParquetViewer_SelfContained.exe"
- name: Upload unsigned artifact for signing
id: upload-unsigned-artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v6
with:
path: |
ParquetViewer.exe
#ParquetViewer_SelfContained.exe
ParquetViewer_SelfContained.exe
- name: Remove unsigned exe's for safety
run: |
Remove-Item -Path "ParquetViewer.exe"
#Remove-Item -Path "ParquetViewer_SelfContained.exe"
Remove-Item -Path "ParquetViewer_SelfContained.exe"
# Documentation: https://about.signpath.io/documentation/trusted-build-systems/github
- name: Submit signing request to SignPath.io
uses: signpath/github-action-submit-signing-request@v1.1
uses: signpath/github-action-submit-signing-request@v2
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: '5ceccea7-c3e7-4165-8c2e-adab8679db20'
@ -152,7 +150,7 @@ jobs:
- uses: ncipollo/release-action@v1
with:
artifacts: "signed-package/ParquetViewer.exe" #",signed-package/ParquetViewer_SelfContained.exe"
artifacts: "signed-package/ParquetViewer.exe,signed-package/ParquetViewer_SelfContained.exe"
body: "PR: #${{ env.PR_NUMBER }}"
allowUpdates: ${{ env.BRANCH_NAME != 'main' }}
omitBodyDuringUpdate: true

View file

@ -26,7 +26,7 @@ jobs:
- name: Run PowerShell script
shell: pwsh
run: |
# Find all .resx files for Turkish (tr)
# Find all .resx files for Turkish (tr) as that is our source of truth
$turkishResxFiles = Get-ChildItem -Path . -Recurse -Filter "*.tr.resx"
# Array to hold all combined translation entries

View file

@ -13,6 +13,7 @@ Some key features:
* Run simple sql queries on parquet data
* Open single or partitioned files
* Generate SQL schema from parquet files
* Easily preview & export image and audio data
# Download
Releases can be found here: https://github.com/mukunku/ParquetViewer/releases

View file

@ -10,9 +10,9 @@
<PackageVersion Include="MiniExcel" Version="2.0.0-preview.2" />
<PackageVersion Include="MSTest.TestAdapter" Version="4.0.2" />
<PackageVersion Include="MSTest.TestFramework" Version="4.0.2" />
<PackageVersion Include="NAudio" Version="2.2.1" />
<PackageVersion Include="NAudio.WinForms" Version="2.2.1" />
<PackageVersion Include="Parquet.Net" Version="5.4.0" />
<PackageVersion Include="NAudio" Version="2.3.0" />
<PackageVersion Include="NAudio.WinForms" Version="2.3.0" />
<PackageVersion Include="Parquet.Net" Version="5.6.0-pre.3" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageVersion Include="RichardSzalay.MockHttp" Version="7.0.0" />
</ItemGroup>

View file

@ -74,7 +74,7 @@ namespace ParquetViewer.Engine.DuckDB
"FLOAT" or "REAL" => (DuckDBType.Float, typeof(float)),
"BLOB" => (DuckDBType.Blob, typeof(ByteArrayValue)),
"DATE" => (DuckDBType.Date, typeof(DateOnly)),
"TIME" => (DuckDBType.Time, typeof(TimeSpan)),
"TIME" => (DuckDBType.Time, typeof(TimeOnly)),
"INTERVAL" => (DuckDBType.Interval, typeof(TimeSpan)),
"UUID" => (DuckDBType.Uuid, typeof(Guid)),
_ => throw new ArgumentOutOfRangeException(nameof(duckDBTypeName), $"Unsupported DuckDB type: {duckDBTypeName}({columnTypeName})")

View file

@ -24,7 +24,7 @@ namespace ParquetViewer.Engine.DuckDB
public IParquetMetadata Metadata => this._metadatas.First();
private List<DuckDBField> _fields;
private readonly List<DuckDBField> _fields;
private static int GetFieldsHashCode(List<DuckDBField> fields)
{
@ -134,7 +134,7 @@ namespace ParquetViewer.Engine.DuckDB
var fieldsHashCode = GetFieldsHashCode(fileFields);
if (!fileGroups.ContainsKey(fieldsHashCode))
{
fileGroups.Add(fieldsHashCode, new List<DuckDBHandle>());
fileGroups.Add(fieldsHashCode, []);
}
fileGroups[fieldsHashCode].Add(db);

View file

@ -9,6 +9,7 @@ namespace ParquetViewer.Engine.ParquetNET
{
public partial class ParquetEngine : IParquetEngine, IDisposable
{
private static readonly ParquetOptions _defaultParquetOptions = new () { UseDateOnlyTypeForDates = true, UseTimeOnlyTypeForTimeMicros = true, UseTimeOnlyTypeForTimeMillis = true };
private readonly ParquetReader[] _parquetFiles;
private long? _recordCount;
@ -95,7 +96,7 @@ namespace ParquetViewer.Engine.ParquetNET
try
{
var parquetReader = await ParquetReader.CreateAsync(parquetFilePath, new() { UseDateOnlyTypeForDates = true }, cancellationToken);
var parquetReader = await ParquetReader.CreateAsync(parquetFilePath, _defaultParquetOptions, cancellationToken);
return new ParquetEngine(parquetFilePath, parquetReader);
}
catch (Exception ex)
@ -119,7 +120,7 @@ namespace ParquetViewer.Engine.ParquetNET
try
{
var parquetReader = await ParquetReader.CreateAsync(file, new() { UseDateOnlyTypeForDates = true }, cancellationToken);
var parquetReader = await ParquetReader.CreateAsync(file, _defaultParquetOptions, cancellationToken);
if (!fileGroups.ContainsKey(parquetReader.Schema))
{
fileGroups.Add(parquetReader.Schema, new List<ParquetReader>());

View file

@ -125,7 +125,7 @@ namespace ParquetViewer.Engine
}
jsonWriter.WriteEndArray();
}
else if (value is IByteArrayValue byteArray /*&& truncateForDisplay //should use the entire byte array if
else if (value is IByteArrayValue byteArray /*&& truncateForDisplay //should we use the entire byte array if
* we're not truncating for display? Seems kind of unreasonable
* for users to rely on binary data within a Struct value preview.*/)
{
@ -149,6 +149,14 @@ namespace ParquetViewer.Engine
else
jsonWriter.WriteStringValue(dateOnly.ToString());
}
else if (value is TimeOnly timeOnly)
{
//Write time as string
if (ParquetEngineSettings.TimeOnlyDisplayFormat is not null)
jsonWriter.WriteStringValue(timeOnly.ToString(ParquetEngineSettings.TimeOnlyDisplayFormat));
else
jsonWriter.WriteStringValue(timeOnly.ToString());
}
else
{
//Everything else just try to write it as string

View file

@ -13,5 +13,6 @@ namespace ParquetViewer.Engine
/// <see cref="IStructValue"/>, and <see cref="IMapValue"/> types to string.</remarks>
public static string? DateDisplayFormat { get; set; }
public static string? DateOnlyDisplayFormat { get; set; }
public static string? TimeOnlyDisplayFormat { get; set; }
}
}

View file

@ -122,6 +122,8 @@ namespace ParquetViewer.Engine
key = dt.ToString(ParquetEngineSettings.DateDisplayFormat);
else if (map.Key is DateOnly dateOnly && ParquetEngineSettings.DateOnlyDisplayFormat is not null)
key = dateOnly.ToString(ParquetEngineSettings.DateOnlyDisplayFormat);
else if (map.Key is TimeOnly timeOnly && ParquetEngineSettings.TimeOnlyDisplayFormat is not null)
key = timeOnly.ToString(ParquetEngineSettings.TimeOnlyDisplayFormat);
else
key = map.Key?.ToString() ?? string.Empty;
@ -130,6 +132,8 @@ namespace ParquetViewer.Engine
value = dt2.ToString(ParquetEngineSettings.DateDisplayFormat);
else if (map.Value is DateOnly dateOnly && ParquetEngineSettings.DateOnlyDisplayFormat is not null)
value = dateOnly.ToString(ParquetEngineSettings.DateOnlyDisplayFormat);
else if (map.Value is TimeOnly timeOnly && ParquetEngineSettings.TimeOnlyDisplayFormat is not null)
value = timeOnly.ToString(ParquetEngineSettings.TimeOnlyDisplayFormat);
else
value = map.Value?.ToString() ?? string.Empty;

View file

@ -44,6 +44,7 @@ namespace ParquetViewer.Tests
//Set a consistent date format for all tests
ParquetEngineSettings.DateDisplayFormat = "yyyy-MM-dd HH:mm:ss";
ParquetEngineSettings.DateOnlyDisplayFormat = "yyyy-MM-dd";
ParquetEngineSettings.TimeOnlyDisplayFormat = "HH:mm:ss";
this._useDuckDBEngine = useDuckDBEngine;
this._canHandleNullComplexTypes = canHandleNullComplexTypes;
@ -714,5 +715,18 @@ namespace ParquetViewer.Tests
Assert.IsNull(lastColumn.Statistics.IsMinValueExact);
Assert.IsNull(lastColumn.Statistics.IsMinValueExact);
}
[SkippableTestMethod]
public async Task DATETTIME_ONLY_TYPE_PYARROW_V22()
{
using var parquetEngine = await OpenFileOrFolderAsync("Data/TIME_ONLY_TYPE_PYARROW_V22.parquet", default);
Assert.AreEqual(4626, parquetEngine.RecordCount);
Assert.HasCount(2, parquetEngine.Fields);
var dataTable = (await parquetEngine.ReadRowsAsync(parquetEngine.Fields, 0, int.MaxValue, default))(false);
Assert.AreEqual(new DateOnly(2024, 1, 1), dataTable.Rows[0][0]);
Assert.AreEqual(new TimeOnly(215720000000), dataTable.Rows[0][1]);
}
}
}

View file

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
VisualStudioVersion = 18.1.11312.151 d18.0
VisualStudioVersion = 18.1.11312.151
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ParquetViewer", "ParquetViewer\ParquetViewer.csproj", "{6019FC1B-3610-4682-BF96-8345C95CB7EC}"
EndProject
@ -16,6 +16,8 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F5D39637-1812-4802-8DB3-254CBBE5C313}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
..\.github\workflows\build-test-publish.yaml = ..\.github\workflows\build-test-publish.yaml
..\.github\workflows\generate-translations-template.yaml = ..\.github\workflows\generate-translations-template.yaml
EndProjectSection
EndProject
Global
@ -25,18 +27,18 @@ Global
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{77900356-25F3-4A24-B638-845C784C1175}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Release_SelfContained|Any CPU.ActiveCfg = Release|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Release_SelfContained|Any CPU.Build.0 = Release|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Release|Any CPU.Build.0 = Release|Any CPU
{6019FC1B-3610-4682-BF96-8345C95CB7EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6019FC1B-3610-4682-BF96-8345C95CB7EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6019FC1B-3610-4682-BF96-8345C95CB7EC}.Release_SelfContained|Any CPU.ActiveCfg = Release_SelfContained|Any CPU
{6019FC1B-3610-4682-BF96-8345C95CB7EC}.Release_SelfContained|Any CPU.Build.0 = Release_SelfContained|Any CPU
{6019FC1B-3610-4682-BF96-8345C95CB7EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6019FC1B-3610-4682-BF96-8345C95CB7EC}.Release|Any CPU.Build.0 = Release|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Debug|Any CPU.Build.0 = Debug|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Release_SelfContained|Any CPU.ActiveCfg = Release|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Release_SelfContained|Any CPU.Build.0 = Release|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Release|Any CPU.ActiveCfg = Release|Any CPU
{77900356-25F3-4A24-B638-845C784C1175}.Release|Any CPU.Build.0 = Release|Any CPU
{16D10BC9-08BF-4248-8975-1B54C42EB2C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{16D10BC9-08BF-4248-8975-1B54C42EB2C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16D10BC9-08BF-4248-8975-1B54C42EB2C2}.Release_SelfContained|Any CPU.ActiveCfg = Release_SelfContained|Any CPU

View file

@ -126,7 +126,6 @@ namespace ParquetViewer.Analytics
UserGuide,
DragDrop,
LoadAllRows,
QueryEditor,
}
}

View file

@ -54,6 +54,7 @@ namespace ParquetViewer.Controls
private DataGridViewCellStyle? hyperlinkCellStyleCache;
private bool isLeftClickButtonDown = false;
private ContextMenuStrip? _contextMenu = null;
private ContextMenuStrip? _headerContextMenu = null;
private static readonly Regex _validColumnNameRegex = new Regex("^[a-zA-Z0-9_]+$");
//We keep track of format overrides with the column name so we can keep formatting the same if the user adds/removes fields from the same file
@ -81,7 +82,6 @@ namespace ParquetViewer.Controls
this.clickableColumnIndexes.Clear();
base.OnDataSourceChanged(e); //This runs OnColumnAdded() for all columns before continuing.
UpdateDateFormats();
SetColumnCellStyles();
AutoSizeColumns();
}
@ -120,13 +120,21 @@ namespace ParquetViewer.Controls
}
}
}
else
{
//Reset any changed stylings
column.DefaultCellStyle = new DataGridViewCellStyle();
}
}
UpdateDateFormats();
}
public void UpdateDateFormats()
{
string dateFormat = AppSettings.DateTimeDisplayFormat.GetDateFormat();
string dateOnlyFormat = AppSettings.DateTimeDisplayFormat.GetDateOnlyFormat();
string timeOnlyFormat = AppSettings.DateTimeDisplayFormat.GetTimeOnlyFormat();
foreach (DataGridViewColumn column in this.Columns)
{
@ -134,11 +142,14 @@ namespace ParquetViewer.Controls
column.DefaultCellStyle.Format = dateFormat;
else if (column.ValueType == typeof(DateOnly))
column.DefaultCellStyle.Format = dateOnlyFormat;
else if (column.ValueType == typeof(TimeOnly))
column.DefaultCellStyle.Format = timeOnlyFormat;
}
//Need to tell the parquet engine how to render date values
ParquetEngineSettings.DateDisplayFormat = dateFormat;
ParquetEngineSettings.DateOnlyDisplayFormat = dateOnlyFormat;
ParquetEngineSettings.TimeOnlyDisplayFormat = timeOnlyFormat;
}
protected override void OnCellPainting(DataGridViewCellPaintingEventArgs e)
@ -417,7 +428,8 @@ namespace ParquetViewer.Controls
this.ClearSelection();
this.FirstDisplayedScrollingRowIndex = cellToReturnTo.RowIndex;
this.FirstDisplayedScrollingColumnIndex = tag.SourceColumnIndex;
if (!this.Columns[tag.SourceColumnIndex].Frozen)
this.FirstDisplayedScrollingColumnIndex = tag.SourceColumnIndex;
this[cellToReturnTo.ColumnIndex, cellToReturnTo.RowIndex].Selected = true;
this.CurrentCell = cellToReturnTo;
this.Focus();
@ -599,14 +611,23 @@ namespace ParquetViewer.Controls
protected override void OnColumnHeaderMouseClick(DataGridViewCellMouseEventArgs e)
{
this.Cursor = Cursors.WaitCursor;
if (e.Button == MouseButtons.Left)
this.Cursor = Cursors.WaitCursor;
try
{
base.OnColumnHeaderMouseClick(e); //This will trigger the sort operation and the OnSorted event if it's a left-click
if (e.Button == MouseButtons.Right)
{
ShowDisplayFormatOptions(e.ColumnIndex);
this._headerContextMenu?.Dispose();
this._headerContextMenu = new ContextMenuStrip();
AddFrozenOption(this._headerContextMenu.Items, e.ColumnIndex);
AddDisplayFormatOptions(this._headerContextMenu.Items, e.ColumnIndex);
if (this._headerContextMenu.Items.Count > 0)
this._headerContextMenu.Show(Cursor.Position);
}
}
finally
@ -714,7 +735,7 @@ namespace ParquetViewer.Controls
//We can just measure a few without going through all of them.
colStringCollection = nonNullColumnValues
.Select(row => row.Field<DateTime>(i).ToString(AppSettings.DateTimeDisplayFormat.GetDateFormat()))
.Take(50);
.Take(25);
}
else if (gridTable.Columns[i].DataType == typeof(DateOnly))
{
@ -724,6 +745,14 @@ namespace ParquetViewer.Controls
.Select(row => row.Field<DateOnly>(i).ToString(AppSettings.DateTimeDisplayFormat.GetDateOnlyFormat()))
.Take(10);
}
else if (gridTable.Columns[i].DataType == typeof(TimeOnly))
{
//All date only's will probably have the same string length so no need to go through all values.
//We can just measure a few without going through all of them.
colStringCollection = nonNullColumnValues
.Select(row => row.Field<TimeOnly>(i).ToString(AppSettings.DateTimeDisplayFormat.GetTimeOnlyFormat()))
.Take(25);
}
else if (gridTable.Columns[i].DataType.ImplementsInterface<IStructValue>())
{
colStringCollection = nonNullColumnValues
@ -875,9 +904,6 @@ namespace ParquetViewer.Controls
this.DefaultCellStyle.ForeColor = this.GridTheme.TextColor;
this.DefaultCellStyle.SelectionBackColor = this.GridTheme.SelectionBackColor;
this.ColumnHeadersDefaultCellStyle.BackColor = this.GridTheme.ColumnHeaderColor;
this.ColumnHeadersDefaultCellStyle.ForeColor = this.GridTheme.TextColor;
this.RowHeadersDefaultCellStyle.BackColor = this.GridTheme.RowHeaderColor;
this.RowHeadersDefaultCellStyle.ForeColor = this.GridTheme.TextColor;
this.RowHeadersDefaultCellStyle.SelectionBackColor = this.GridTheme.SelectionBackColor;
@ -897,6 +923,7 @@ namespace ParquetViewer.Controls
WrapMode = DataGridViewTriState.True
};
StyleFrozenColumns();
SetColumnCellStyles();
}
@ -1056,12 +1083,13 @@ namespace ParquetViewer.Controls
return queryBuilder.ToString();
}
private void ShowDisplayFormatOptions(int columnIndex)
private void AddDisplayFormatOptions(ToolStripItemCollection contextMenu, int columnIndex)
{
//If this is a byte array column, show available formatting options
if (this.Columns[columnIndex].ValueType.ImplementsInterface<IByteArrayValue>()
&& this.Columns[columnIndex].CellTemplate?.GetType() != typeof(AudioPlayerDataGridViewCell))
{
AddSeperatorIfNeeded();
const int RECORDS_TO_INTERSECT_COUNT = 8;
//Find a few different non-null values and find the common display formats that all of them support.
@ -1086,7 +1114,6 @@ namespace ParquetViewer.Controls
possibleDisplayFormats = [default];
}
var columnHeaderContextMenu = new ContextMenuStrip();
foreach (var supportedFormat in possibleDisplayFormats)
{
var columnName = this.Columns[columnIndex].Name;
@ -1102,20 +1129,17 @@ namespace ParquetViewer.Controls
this.Refresh(); //Force a re-draw to render updated format
this.AutoSizeColumns(columnIndex); //Re-size the column
};
columnHeaderContextMenu.Items.Add(toolstripMenuItem);
contextMenu.Add(toolstripMenuItem);
if (!byteArrayColumnsWithFormatOverrides.TryGetValue(columnName, out var displayFormat))
displayFormat = default;
toolstripMenuItem.Checked = displayFormat == supportedFormat;
}
columnHeaderContextMenu.Show(Cursor.Position);
}
else if (this.Columns[columnIndex].ValueType == typeof(float) || this.Columns[columnIndex].ValueType == typeof(double))
{
var columnHeaderContextMenu = new ContextMenuStrip();
AddSeperatorIfNeeded();
var columnName = this.Columns[columnIndex].Name;
if (!floatColumnsWithFormatOverrides.TryGetValue(columnName, out var displayFormat))
displayFormat = default;
@ -1134,7 +1158,7 @@ namespace ParquetViewer.Controls
this.Refresh(); //Force a re-draw to render updated format
this.AutoSizeColumns(columnIndex); //Re-size the column
};
columnHeaderContextMenu.Items.Add(scientificNotationMenuItem);
contextMenu.Add(scientificNotationMenuItem);
var decimalNotationMenuItem = new ToolStripMenuItem(Resources.Strings.DecimalFormatting)
{ Checked = displayFormat == FloatDisplayFormat.Decimal };
@ -1150,9 +1174,56 @@ namespace ParquetViewer.Controls
this.Refresh(); //Force a re-draw to render updated format
this.AutoSizeColumns(columnIndex); //Re-size the column
};
columnHeaderContextMenu.Items.Add(decimalNotationMenuItem);
contextMenu.Add(decimalNotationMenuItem);
}
columnHeaderContextMenu.Show(Cursor.Position);
void AddSeperatorIfNeeded()
{
if (contextMenu.Count > 0)
contextMenu.Add(new ToolStripSeparator());
}
}
private void AddFrozenOption(ToolStripItemCollection items, int columnIndex)
{
var column = this.Columns[columnIndex];
//Only show the option to freeze if the horizontal scroll bar is visible or if the column is already frozen
if (!column.Frozen && !this.HorizontalScrollBar.Visible)
return;
var menuItem = new ToolStripMenuItem(Resources.Strings.FrozenColumnText)
{ Checked = column.Frozen };
menuItem.Click += (object? _, EventArgs _) =>
{
column.Frozen = !column.Frozen;
this.StyleFrozenColumns();
};
items.Add(menuItem);
}
private void StyleFrozenColumns()
{
//First reset styles for all column headers
for (var i = 0; i < this.Columns.Count; i++)
{
this.Columns[i].HeaderCell.Style = new DataGridViewCellStyle();
}
//Reset cells
SetColumnCellStyles();
//Now style frozen ones (We need to go by DisplayIndex in case the user re-arranged the columns)
var columnsInOrderByDisplayIndex = this.Columns.AsEnumerable().OrderBy(col => col.DisplayIndex);
foreach (var column in columnsInOrderByDisplayIndex)
{
if (!column.Frozen)
break;
column.DefaultCellStyle.BackColor = this.GridTheme.FrozenCellBackgroundColor;
column.HeaderCell.Style.BackColor = this.GridTheme.FrozenColumnHeaderColor;
}
}
@ -1333,6 +1404,9 @@ namespace ParquetViewer.Controls
//dispose any AudioPlayerDataGridViewCells to free resources and stop ongoing playback.
this.DisposeAudioCells();
this._contextMenu?.Dispose();
this._headerContextMenu?.Dispose();
base.Dispose(disposing);
}

View file

@ -248,7 +248,7 @@ namespace ParquetViewer
AppSettings.AlwaysSelectAllFields = false;
this.NewSelectedFields.Clear();
if (this.allFieldsRadioButton.Checked || (this.fieldsPanel.Controls.Find(SelectAllCheckboxName, true).FirstOrDefault() as CheckBox)?.Checked == true)
if (this.allFieldsRadioButton.Checked)
{
this.NewSelectedFields.AddRange(this.AvailableFields);
}

View file

@ -15,6 +15,7 @@ namespace ParquetViewer.Helpers
{ typeof(bool), "BIT {1}NULL" },
{ typeof(char), "CHAR {1}NULL" },
{ typeof(DateTime), "DATETIME {1}NULL" },
{ typeof(DateOnly), "DATE {1}NULL" },
{ typeof(double), "FLOAT {1}NULL" },
{ typeof(uint), "INT {1}NULL" },
{ typeof(int), "INT {1}NULL" },
@ -27,6 +28,7 @@ namespace ParquetViewer.Helpers
{ typeof(sbyte), "TINYINT {1}NULL" },
{ typeof(string), "NVARCHAR({0}) {1}NULL" },
{ typeof(TimeSpan), "INT {1}NULL" },
{ typeof(TimeOnly), "INT {1}NULL" },
{ typeof(byte[]), "VARBINARY {1}NULL" },
{ typeof(IListValue), "sql_variant {1}NULL /*LIST*/" },
{ typeof(IMapValue), "sql_variant {1}NULL /*MAP*/" },

View file

@ -1,5 +1,4 @@
using Microsoft.Win32;
using ParquetViewer.Engine.ParquetNET.Types;
using ParquetViewer.Engine.Types;
using System;
using System.Collections.Generic;
@ -7,7 +6,6 @@ using System.ComponentModel;
using System.Data;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Windows.Forms;
@ -18,8 +16,10 @@ namespace ParquetViewer.Helpers
{
private const string DefaultDateTimeFormat = "g";
private const string DefaultDateOnlyFormat = "d";
private const string DefaultTimeOnlyFormat = "T";
public const string ISO8601DateTimeFormat = "yyyy-MM-ddTHH:mm:ss.FFFFFFF";
public const string ISO8601DateOnlyFormat = "yyyy-MM-dd";
public const string ISO8601TimeOnlyFormat = "HH:mm:ss.FFFFFFF";
/// <summary>
/// Returns a list of all column names within a given datatable
@ -54,7 +54,16 @@ namespace ParquetViewer.Helpers
DateFormat.ISO8601 => ISO8601DateOnlyFormat,
DateFormat.Default => DefaultDateOnlyFormat,
DateFormat.Custom => AppSettings.CustomDateFormat is not null ?
UtilityMethods.StripTimeComponentsFromDateFormat(AppSettings.CustomDateFormat) : DefaultDateOnlyFormat,
UtilityMethods.StripTimeComponentsFromDateTimeFormat(AppSettings.CustomDateFormat) : DefaultDateOnlyFormat,
_ => string.Empty
};
public static string GetTimeOnlyFormat(this DateFormat dateFormat) => dateFormat switch
{
DateFormat.ISO8601 => ISO8601TimeOnlyFormat,
DateFormat.Default => DefaultTimeOnlyFormat,
DateFormat.Custom => AppSettings.CustomDateFormat is not null ?
UtilityMethods.StripDateComponentsFromDateTimeFormat(AppSettings.CustomDateFormat) : DefaultTimeOnlyFormat,
_ => string.Empty
};
@ -90,6 +99,14 @@ namespace ParquetViewer.Helpers
}
}
public static IEnumerable<DataGridViewColumn> AsEnumerable(this DataGridViewColumnCollection columns)
{
foreach (DataGridViewColumn column in columns)
{
yield return column;
}
}
/// <summary>
/// Returns true if the type is a "simple" type. Basically anything that isn't a class, struct or array.
/// </summary>

View file

@ -19,6 +19,8 @@ namespace ParquetViewer.Helpers
public Color SelectionBackColor { get; }
public Color FormBackgroundColor { get; }
public Color DisabledTextColor { get; }
public Color FrozenColumnHeaderColor { get; }
public Color FrozenCellBackgroundColor { get; }
private readonly Func<Theme, ToolStripProfessionalRenderer>? _toolStripRendererProvider = null;
public bool HasToolStripRendererProvider => _toolStripRendererProvider is not null;
@ -41,13 +43,14 @@ namespace ParquetViewer.Helpers
Color formBackgroundColor,
Func<Theme, ToolStripProfessionalRenderer>? toolStripRendererProvider,
Color activeHyperlinkColor,
Color disabledTextColor)
Color disabledTextColor,
Color frozenColumnHeaderColor,
Color frozenCellBackgroundColor)
{
this.CellBackgroundColor = cellBackgroundColor;
this.TextColor = textColor;
this.AlternateRowsCellBackgroundColor = alternateRowsCellBackgroundColor;
this.ColumnHeaderColor = columnHeaderColor;
this.ColumnHeaderColor = columnHeaderColor;
this.RowHeaderColor = rowHeaderColor;
this.RowHeaderBorderStyle = rowHeaderBorderStyle;
this.GridBackgroundColor = gridBackgroundColor;
@ -59,6 +62,8 @@ namespace ParquetViewer.Helpers
this._toolStripRendererProvider = toolStripRendererProvider;
this.ActiveHyperlinkColor = activeHyperlinkColor;
this.DisabledTextColor = disabledTextColor;
this.FrozenColumnHeaderColor = frozenColumnHeaderColor;
this.FrozenCellBackgroundColor = frozenCellBackgroundColor;
}
public static Theme DarkModeTheme => new(
@ -76,7 +81,9 @@ namespace ParquetViewer.Helpers
Color.FromArgb(44, 44, 44),
(theme) => { return new DarkModeToolStripRenderer(theme); },
Color.LightGray,
Color.DarkGray
Color.DarkGray,
Color.FromArgb(33, 37, 63),
Color.FromArgb(40, 44, 48)
);
public static Theme LightModeTheme => new(
@ -94,7 +101,9 @@ namespace ParquetViewer.Helpers
SystemColors.Control,
null,
Color.Red,
Color.DarkGray
Color.DarkGray,
SystemColors.InactiveCaption,
SystemColors.InactiveBorder
);
public bool Equals(Theme other) => this.GetHashCode() == other.GetHashCode(); //Not perfect but good enough

View file

@ -100,11 +100,11 @@ namespace ParquetViewer.Helpers
}
/// <summary>
/// Best effort attempt at stripping time components from a date format string.
/// Best effort attempt at stripping time components from a datetime format string.
/// </summary>
/// <param name="dateFormat">Date format with potential time components</param>
/// <returns>Date format with no time components</returns>
public static string StripTimeComponentsFromDateFormat(string dateFormat)
public static string StripTimeComponentsFromDateTimeFormat(string dateFormat)
{
var timeComponents = new string[] { "H", "h", "m", "s", "f", "F", "t", "z", "K" };
foreach (var component in timeComponents)
@ -115,5 +115,22 @@ namespace ParquetViewer.Helpers
dateFormat = dateFormat.TrimEnd('/', '-', '.', ' ', ',', '_');
return dateFormat.Trim();
}
/// <summary>
/// Best effort attempt at stripping date components from a datetime format string.
/// </summary>
/// <param name="dateFormat">Date format with potential date components</param>
/// <returns>Time format with no date components</returns>
public static string StripDateComponentsFromDateTimeFormat(string dateFormat)
{
var dateComponents = new string[] { "y", "M", "d", "g" };
foreach (var component in dateComponents)
{
dateFormat = dateFormat.Replace(component, string.Empty);
}
dateFormat = dateFormat.Replace(" ", " ");
dateFormat = dateFormat.TrimStart('/', '-', '.', ' ', ',', '_');
return dateFormat.Trim();
}
}
}

View file

@ -35,7 +35,7 @@ namespace ParquetViewer
{
components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
DataGridViewCellStyle dataGridViewCellStyle2 = new DataGridViewCellStyle();
DataGridViewCellStyle dataGridViewCellStyle1 = new DataGridViewCellStyle();
mainTableLayoutPanel = new TableLayoutPanel();
recordsToLabel = new Label();
recordCountTextBox = new DelayedOnChangedTextBox();
@ -68,7 +68,6 @@ namespace ParquetViewer
toolsToolStripMenuItem = new ToolStripMenuItem();
getSQLCreateTableScriptToolStripMenuItem = new ToolStripMenuItem();
metadataViewerToolStripMenuItem = new ToolStripMenuItem();
openQueryEditorToolToolStripMenuItem = new ToolStripMenuItem();
helpToolStripMenuItem = new ToolStripMenuItem();
userGuideToolStripMenuItem = new ToolStripMenuItem();
shareAnonymousUsageDataToolStripMenuItem = new ToolStripMenuItem();
@ -108,20 +107,17 @@ namespace ParquetViewer
mainTableLayoutPanel.Controls.Add(mainGridView, 0, 1);
mainTableLayoutPanel.Controls.Add(loadAllRowsButton, 10, 0);
mainTableLayoutPanel.Name = "mainTableLayoutPanel";
loadAllRowsButtonTooltip.SetToolTip(mainTableLayoutPanel, resources.GetString("mainTableLayoutPanel.ToolTip"));
//
// recordsToLabel
//
resources.ApplyResources(recordsToLabel, "recordsToLabel");
recordsToLabel.Name = "recordsToLabel";
loadAllRowsButtonTooltip.SetToolTip(recordsToLabel, resources.GetString("recordsToLabel.ToolTip"));
//
// recordCountTextBox
//
resources.ApplyResources(recordCountTextBox, "recordCountTextBox");
recordCountTextBox.DelayedTextChangedTimeout = 1000;
recordCountTextBox.Name = "recordCountTextBox";
loadAllRowsButtonTooltip.SetToolTip(recordCountTextBox, resources.GetString("recordCountTextBox.ToolTip"));
recordCountTextBox.DelayedTextChanged += recordsToTextBox_TextChanged;
recordCountTextBox.KeyPress += recordsToTextBox_KeyPress;
//
@ -129,14 +125,12 @@ namespace ParquetViewer
//
resources.ApplyResources(showRecordsFromLabel, "showRecordsFromLabel");
showRecordsFromLabel.Name = "showRecordsFromLabel";
loadAllRowsButtonTooltip.SetToolTip(showRecordsFromLabel, resources.GetString("showRecordsFromLabel.ToolTip"));
//
// offsetTextBox
//
resources.ApplyResources(offsetTextBox, "offsetTextBox");
offsetTextBox.DelayedTextChangedTimeout = 1000;
offsetTextBox.Name = "offsetTextBox";
loadAllRowsButtonTooltip.SetToolTip(offsetTextBox, resources.GetString("offsetTextBox.ToolTip"));
offsetTextBox.DelayedTextChanged += offsetTextBox_TextChanged;
offsetTextBox.KeyPress += offsetTextBox_KeyPress;
//
@ -146,7 +140,6 @@ namespace ParquetViewer
runQueryButton.ForeColor = System.Drawing.Color.DarkRed;
runQueryButton.Image = Resources.Icons.exclamation_icon;
runQueryButton.Name = "runQueryButton";
loadAllRowsButtonTooltip.SetToolTip(runQueryButton, resources.GetString("runQueryButton.ToolTip"));
runQueryButton.UseVisualStyleBackColor = true;
runQueryButton.Click += runQueryButton_Click;
//
@ -157,7 +150,6 @@ namespace ParquetViewer
searchFilterLabel.LinkColor = System.Drawing.Color.Navy;
searchFilterLabel.Name = "searchFilterLabel";
searchFilterLabel.TabStop = true;
loadAllRowsButtonTooltip.SetToolTip(searchFilterLabel, resources.GetString("searchFilterLabel.ToolTip"));
searchFilterLabel.LinkClicked += searchFilterLabel_Click;
//
// searchFilterTextBox
@ -165,7 +157,6 @@ namespace ParquetViewer
resources.ApplyResources(searchFilterTextBox, "searchFilterTextBox");
mainTableLayoutPanel.SetColumnSpan(searchFilterTextBox, 2);
searchFilterTextBox.Name = "searchFilterTextBox";
loadAllRowsButtonTooltip.SetToolTip(searchFilterTextBox, resources.GetString("searchFilterTextBox.ToolTip"));
searchFilterTextBox.Enter += searchFilterTextBox_Enter;
searchFilterTextBox.KeyPress += searchFilterTextBox_KeyPress;
searchFilterTextBox.Leave += searchFilterTextBox_Leave;
@ -175,38 +166,37 @@ namespace ParquetViewer
resources.ApplyResources(clearFilterButton, "clearFilterButton");
clearFilterButton.ForeColor = System.Drawing.Color.Black;
clearFilterButton.Name = "clearFilterButton";
loadAllRowsButtonTooltip.SetToolTip(clearFilterButton, resources.GetString("clearFilterButton.ToolTip"));
clearFilterButton.UseVisualStyleBackColor = true;
clearFilterButton.Click += clearFilterButton_Click;
//
// mainGridView
//
resources.ApplyResources(mainGridView, "mainGridView");
mainGridView.AllowUserToAddRows = false;
mainGridView.AllowUserToDeleteRows = false;
mainGridView.AllowUserToOrderColumns = true;
resources.ApplyResources(mainGridView, "mainGridView");
mainGridView.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
mainGridView.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;
dataGridViewCellStyle2.Alignment = DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle2.BackColor = System.Drawing.SystemColors.ControlLight;
dataGridViewCellStyle2.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
dataGridViewCellStyle2.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle2.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle2.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle2.WrapMode = DataGridViewTriState.True;
mainGridView.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle2;
dataGridViewCellStyle1.Alignment = DataGridViewContentAlignment.MiddleLeft;
dataGridViewCellStyle1.BackColor = System.Drawing.SystemColors.ControlLight;
dataGridViewCellStyle1.Font = new System.Drawing.Font("Segoe UI Semibold", 9F, System.Drawing.FontStyle.Bold);
dataGridViewCellStyle1.ForeColor = System.Drawing.SystemColors.WindowText;
dataGridViewCellStyle1.SelectionBackColor = System.Drawing.SystemColors.Highlight;
dataGridViewCellStyle1.SelectionForeColor = System.Drawing.SystemColors.HighlightText;
dataGridViewCellStyle1.WrapMode = DataGridViewTriState.True;
mainGridView.ColumnHeadersDefaultCellStyle = dataGridViewCellStyle1;
mainGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
mainGridView.ColumnNameEscapeFormat = "[{0}]";
mainTableLayoutPanel.SetColumnSpan(mainGridView, 11);
mainGridView.CopyAsWhereIcon = (System.Drawing.Image)resources.GetObject("mainGridView.CopyAsWhereIcon");
mainGridView.CopyToClipboardIcon = (System.Drawing.Image)resources.GetObject("mainGridView.CopyToClipboardIcon");
mainGridView.DateValueEscapeFormat = "#{0}#";
mainGridView.EnableHeadersVisualStyles = false;
mainGridView.Name = "mainGridView";
mainGridView.ReadOnly = true;
mainTableLayoutPanel.SetRowSpan(mainGridView, 2);
mainGridView.ShowCellToolTips = false;
mainGridView.ShowCopyAsWhereContextMenuItem = true;
loadAllRowsButtonTooltip.SetToolTip(mainGridView, resources.GetString("mainGridView.ToolTip"));
mainGridView.DataBindingComplete += mainGridView_DataBindingComplete;
//
// loadAllRowsButton
@ -228,17 +218,16 @@ namespace ParquetViewer
//
// mainMenuStrip
//
resources.ApplyResources(mainMenuStrip, "mainMenuStrip");
mainMenuStrip.BackColor = System.Drawing.SystemColors.Control;
mainMenuStrip.Items.AddRange(new ToolStripItem[] { fileToolStripMenuItem, editToolStripMenuItem, toolsToolStripMenuItem, helpToolStripMenuItem });
resources.ApplyResources(mainMenuStrip, "mainMenuStrip");
mainMenuStrip.Name = "mainMenuStrip";
loadAllRowsButtonTooltip.SetToolTip(mainMenuStrip, resources.GetString("mainMenuStrip.ToolTip"));
//
// fileToolStripMenuItem
//
resources.ApplyResources(fileToolStripMenuItem, "fileToolStripMenuItem");
fileToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { newToolStripMenuItem, openToolStripMenuItem, openFolderToolStripMenuItem, toolStripSeparator, saveAsToolStripMenuItem, toolStripSeparator1, exitToolStripMenuItem });
fileToolStripMenuItem.Name = "fileToolStripMenuItem";
resources.ApplyResources(fileToolStripMenuItem, "fileToolStripMenuItem");
//
// newToolStripMenuItem
//
@ -254,14 +243,14 @@ namespace ParquetViewer
//
// openFolderToolStripMenuItem
//
resources.ApplyResources(openFolderToolStripMenuItem, "openFolderToolStripMenuItem");
openFolderToolStripMenuItem.Name = "openFolderToolStripMenuItem";
resources.ApplyResources(openFolderToolStripMenuItem, "openFolderToolStripMenuItem");
openFolderToolStripMenuItem.Click += openFolderToolStripMenuItem_Click;
//
// toolStripSeparator
//
resources.ApplyResources(toolStripSeparator, "toolStripSeparator");
toolStripSeparator.Name = "toolStripSeparator";
resources.ApplyResources(toolStripSeparator, "toolStripSeparator");
//
// saveAsToolStripMenuItem
//
@ -271,20 +260,20 @@ namespace ParquetViewer
//
// toolStripSeparator1
//
resources.ApplyResources(toolStripSeparator1, "toolStripSeparator1");
toolStripSeparator1.Name = "toolStripSeparator1";
resources.ApplyResources(toolStripSeparator1, "toolStripSeparator1");
//
// exitToolStripMenuItem
//
resources.ApplyResources(exitToolStripMenuItem, "exitToolStripMenuItem");
exitToolStripMenuItem.Name = "exitToolStripMenuItem";
resources.ApplyResources(exitToolStripMenuItem, "exitToolStripMenuItem");
exitToolStripMenuItem.Click += exitToolStripMenuItem_Click;
//
// editToolStripMenuItem
//
resources.ApplyResources(editToolStripMenuItem, "editToolStripMenuItem");
editToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { changeFieldsMenuStripButton, changeDateFormatToolStripMenuItem, alwaysLoadAllRecordsToolStripMenuItem, darkModeToolStripMenuItem });
editToolStripMenuItem.Name = "editToolStripMenuItem";
resources.ApplyResources(editToolStripMenuItem, "editToolStripMenuItem");
//
// changeFieldsMenuStripButton
//
@ -294,50 +283,50 @@ namespace ParquetViewer
//
// changeDateFormatToolStripMenuItem
//
resources.ApplyResources(changeDateFormatToolStripMenuItem, "changeDateFormatToolStripMenuItem");
changeDateFormatToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { defaultToolStripMenuItem, iSO8601ToolStripMenuItem, customDateFormatToolStripMenuItem });
resources.ApplyResources(changeDateFormatToolStripMenuItem, "changeDateFormatToolStripMenuItem");
changeDateFormatToolStripMenuItem.Name = "changeDateFormatToolStripMenuItem";
//
// defaultToolStripMenuItem
//
resources.ApplyResources(defaultToolStripMenuItem, "defaultToolStripMenuItem");
defaultToolStripMenuItem.Name = "defaultToolStripMenuItem";
resources.ApplyResources(defaultToolStripMenuItem, "defaultToolStripMenuItem");
defaultToolStripMenuItem.Tag = "0";
defaultToolStripMenuItem.Click += DateFormatMenuItem_Click;
//
// iSO8601ToolStripMenuItem
//
resources.ApplyResources(iSO8601ToolStripMenuItem, "iSO8601ToolStripMenuItem");
iSO8601ToolStripMenuItem.Name = "iSO8601ToolStripMenuItem";
resources.ApplyResources(iSO8601ToolStripMenuItem, "iSO8601ToolStripMenuItem");
iSO8601ToolStripMenuItem.Tag = "2";
iSO8601ToolStripMenuItem.Click += DateFormatMenuItem_Click;
//
// customDateFormatToolStripMenuItem
//
resources.ApplyResources(customDateFormatToolStripMenuItem, "customDateFormatToolStripMenuItem");
customDateFormatToolStripMenuItem.Name = "customDateFormatToolStripMenuItem";
resources.ApplyResources(customDateFormatToolStripMenuItem, "customDateFormatToolStripMenuItem");
customDateFormatToolStripMenuItem.Tag = "6";
customDateFormatToolStripMenuItem.Click += DateFormatMenuItem_Click;
//
// alwaysLoadAllRecordsToolStripMenuItem
//
resources.ApplyResources(alwaysLoadAllRecordsToolStripMenuItem, "alwaysLoadAllRecordsToolStripMenuItem");
alwaysLoadAllRecordsToolStripMenuItem.Checked = true;
alwaysLoadAllRecordsToolStripMenuItem.CheckState = CheckState.Checked;
alwaysLoadAllRecordsToolStripMenuItem.Name = "alwaysLoadAllRecordsToolStripMenuItem";
resources.ApplyResources(alwaysLoadAllRecordsToolStripMenuItem, "alwaysLoadAllRecordsToolStripMenuItem");
alwaysLoadAllRecordsToolStripMenuItem.Click += alwaysLoadAllRecordsToolStripMenuItem_Click;
//
// darkModeToolStripMenuItem
//
resources.ApplyResources(darkModeToolStripMenuItem, "darkModeToolStripMenuItem");
darkModeToolStripMenuItem.Name = "darkModeToolStripMenuItem";
resources.ApplyResources(darkModeToolStripMenuItem, "darkModeToolStripMenuItem");
darkModeToolStripMenuItem.Click += darkModeToolStripMenuItem_Click;
//
// toolsToolStripMenuItem
//
resources.ApplyResources(toolsToolStripMenuItem, "toolsToolStripMenuItem");
toolsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { getSQLCreateTableScriptToolStripMenuItem, metadataViewerToolStripMenuItem, openQueryEditorToolToolStripMenuItem });
toolsToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { getSQLCreateTableScriptToolStripMenuItem, metadataViewerToolStripMenuItem });
toolsToolStripMenuItem.Name = "toolsToolStripMenuItem";
resources.ApplyResources(toolsToolStripMenuItem, "toolsToolStripMenuItem");
//
// getSQLCreateTableScriptToolStripMenuItem
//
@ -352,63 +341,57 @@ namespace ParquetViewer
metadataViewerToolStripMenuItem.Name = "metadataViewerToolStripMenuItem";
metadataViewerToolStripMenuItem.Click += MetadataViewerToolStripMenuItem_Click;
//
// openQueryEditorToolToolStripMenuItem
//
resources.ApplyResources(openQueryEditorToolToolStripMenuItem, "openQueryEditorToolToolStripMenuItem");
openQueryEditorToolToolStripMenuItem.Name = "openQueryEditorToolToolStripMenuItem";
openQueryEditorToolToolStripMenuItem.Click += openQueryEditorToolToolStripMenuItem_Click;
//
// helpToolStripMenuItem
//
resources.ApplyResources(helpToolStripMenuItem, "helpToolStripMenuItem");
helpToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { userGuideToolStripMenuItem, shareAnonymousUsageDataToolStripMenuItem, languageToolStripMenuItem, aboutToolStripMenuItem });
helpToolStripMenuItem.Name = "helpToolStripMenuItem";
resources.ApplyResources(helpToolStripMenuItem, "helpToolStripMenuItem");
//
// userGuideToolStripMenuItem
//
resources.ApplyResources(userGuideToolStripMenuItem, "userGuideToolStripMenuItem");
userGuideToolStripMenuItem.Image = Resources.Icons.external_link_icon;
userGuideToolStripMenuItem.Name = "userGuideToolStripMenuItem";
resources.ApplyResources(userGuideToolStripMenuItem, "userGuideToolStripMenuItem");
userGuideToolStripMenuItem.Click += userGuideToolStripMenuItem_Click;
//
// shareAnonymousUsageDataToolStripMenuItem
//
resources.ApplyResources(shareAnonymousUsageDataToolStripMenuItem, "shareAnonymousUsageDataToolStripMenuItem");
shareAnonymousUsageDataToolStripMenuItem.Name = "shareAnonymousUsageDataToolStripMenuItem";
resources.ApplyResources(shareAnonymousUsageDataToolStripMenuItem, "shareAnonymousUsageDataToolStripMenuItem");
shareAnonymousUsageDataToolStripMenuItem.CheckedChanged += shareAnonymousUsageDataToolStripMenuItem_CheckedChanged;
shareAnonymousUsageDataToolStripMenuItem.Click += shareAnonymousUsageDataToolStripMenuItem_Click;
//
// languageToolStripMenuItem
//
resources.ApplyResources(languageToolStripMenuItem, "languageToolStripMenuItem");
languageToolStripMenuItem.DropDownItems.AddRange(new ToolStripItem[] { englishToolStripMenuItem, turkishToolStripMenuItem });
languageToolStripMenuItem.Image = Resources.Icons.localization_icon;
languageToolStripMenuItem.Name = "languageToolStripMenuItem";
resources.ApplyResources(languageToolStripMenuItem, "languageToolStripMenuItem");
//
// englishToolStripMenuItem
//
resources.ApplyResources(englishToolStripMenuItem, "englishToolStripMenuItem");
englishToolStripMenuItem.Name = "englishToolStripMenuItem";
resources.ApplyResources(englishToolStripMenuItem, "englishToolStripMenuItem");
englishToolStripMenuItem.Tag = "en-US";
englishToolStripMenuItem.Click += languageToolStripMenuItem_Click;
//
// turkishToolStripMenuItem
//
resources.ApplyResources(turkishToolStripMenuItem, "turkishToolStripMenuItem");
turkishToolStripMenuItem.Name = "turkishToolStripMenuItem";
resources.ApplyResources(turkishToolStripMenuItem, "turkishToolStripMenuItem");
turkishToolStripMenuItem.Tag = "tr-TR";
turkishToolStripMenuItem.Click += languageToolStripMenuItem_Click;
//
// aboutToolStripMenuItem
//
resources.ApplyResources(aboutToolStripMenuItem, "aboutToolStripMenuItem");
aboutToolStripMenuItem.Name = "aboutToolStripMenuItem";
resources.ApplyResources(aboutToolStripMenuItem, "aboutToolStripMenuItem");
aboutToolStripMenuItem.Click += aboutToolStripMenuItem_Click;
//
// showingRecordCountStatusBarLabel
//
resources.ApplyResources(showingRecordCountStatusBarLabel, "showingRecordCountStatusBarLabel");
showingRecordCountStatusBarLabel.Name = "showingRecordCountStatusBarLabel";
resources.ApplyResources(showingRecordCountStatusBarLabel, "showingRecordCountStatusBarLabel");
//
// actualShownRecordCountLabel
//
@ -417,19 +400,19 @@ namespace ParquetViewer
//
// recordsTextStatusBarLabel
//
resources.ApplyResources(recordsTextStatusBarLabel, "recordsTextStatusBarLabel");
recordsTextStatusBarLabel.Name = "recordsTextStatusBarLabel";
resources.ApplyResources(recordsTextStatusBarLabel, "recordsTextStatusBarLabel");
//
// springStatusBarLabel
//
resources.ApplyResources(springStatusBarLabel, "springStatusBarLabel");
springStatusBarLabel.Name = "springStatusBarLabel";
resources.ApplyResources(springStatusBarLabel, "springStatusBarLabel");
springStatusBarLabel.Spring = true;
//
// showingStatusBarLabel
//
resources.ApplyResources(showingStatusBarLabel, "showingStatusBarLabel");
showingStatusBarLabel.Name = "showingStatusBarLabel";
resources.ApplyResources(showingStatusBarLabel, "showingStatusBarLabel");
showingStatusBarLabel.Click += showingStatusBarLabel_Click;
//
// recordCountStatusBarLabel
@ -439,8 +422,8 @@ namespace ParquetViewer
//
// outOfStatusBarLabel
//
resources.ApplyResources(outOfStatusBarLabel, "outOfStatusBarLabel");
outOfStatusBarLabel.Name = "outOfStatusBarLabel";
resources.ApplyResources(outOfStatusBarLabel, "outOfStatusBarLabel");
//
// totalRowCountStatusBarLabel
//
@ -449,11 +432,10 @@ namespace ParquetViewer
//
// mainStatusStrip
//
resources.ApplyResources(mainStatusStrip, "mainStatusStrip");
mainStatusStrip.Items.AddRange(new ToolStripItem[] { showingRecordCountStatusBarLabel, actualShownRecordCountLabel, recordsTextStatusBarLabel, springStatusBarLabel, showingStatusBarLabel, recordCountStatusBarLabel, outOfStatusBarLabel, totalRowCountStatusBarLabel });
resources.ApplyResources(mainStatusStrip, "mainStatusStrip");
mainStatusStrip.Name = "mainStatusStrip";
mainStatusStrip.ShowItemToolTips = true;
loadAllRowsButtonTooltip.SetToolTip(mainStatusStrip, resources.GetString("mainStatusStrip.ToolTip"));
//
// exportFileDialog
//
@ -468,8 +450,8 @@ namespace ParquetViewer
//
// MainForm
//
resources.ApplyResources(this, "$this");
AllowDrop = true;
resources.ApplyResources(this, "$this");
AutoScaleMode = AutoScaleMode.Font;
Controls.Add(mainStatusStrip);
Controls.Add(mainTableLayoutPanel);
@ -478,7 +460,6 @@ namespace ParquetViewer
KeyPreview = true;
MainMenuStrip = mainMenuStrip;
Name = "MainForm";
loadAllRowsButtonTooltip.SetToolTip(this, resources.GetString("$this.ToolTip"));
Load += MainForm_Load;
DragDrop += MainForm_DragDrop;
DragEnter += MainForm_DragEnter;
@ -548,7 +529,6 @@ namespace ParquetViewer
private ToolStripMenuItem languageToolStripMenuItem;
private ToolStripMenuItem englishToolStripMenuItem;
private ToolStripMenuItem turkishToolStripMenuItem;
private ToolStripMenuItem openQueryEditorToolToolStripMenuItem;
}
}

View file

@ -46,7 +46,7 @@ namespace ParquetViewer
private void recordsToTextBox_TextChanged(object sender, EventArgs? e)
{
var textbox = (TextBox)sender;
if (int.TryParse(textbox.Text, out var recordCount) && recordCount >= 0)
if (int.TryParse(textbox.Text, out var recordCount) && recordCount > 0)
this.CurrentMaxRowCount = recordCount;
else
textbox.Text = this.CurrentMaxRowCount.ToString();
@ -288,34 +288,5 @@ namespace ParquetViewer
AppSettings.UserSelectedCulture = newCultureInfo;
UtilityMethods.RestartApplication();
}
private QueryEditor? _openQueryEditor = null;
private string? _queryEditorSavedQueryText = null;
private void openQueryEditorToolToolStripMenuItem_Click(object sender, EventArgs e)
{
if (this._openQueryEditor == null || this._openQueryEditor.IsDisposed)
{
this._openQueryEditor = new QueryEditor(this.SelectedFields, this.OpenFileOrFolderPath, this.CurrentOffset, this.CurrentMaxRowCount);
this._openQueryEditor.FormClosed += (s, args) =>
{
//Remember the user's query in case they accidentally close the window
this._queryEditorSavedQueryText = this._openQueryEditor.QueryText;
this._openQueryEditor.Dispose();
this._openQueryEditor = null;
};
if (!string.IsNullOrWhiteSpace(this._queryEditorSavedQueryText))
{
this._openQueryEditor.QueryText = this._queryEditorSavedQueryText;
}
this._openQueryEditor.StartPosition = FormStartPosition.Manual;
this._openQueryEditor.Location = this.Location + new Size(30, 30);
this._openQueryEditor.Show(); //don't assign parent so the window can be handled separately by the user
MenuBarClickEvent.FireAndForget(MenuBarClickEvent.ActionId.QueryEditor);
}
else
{
this._openQueryEditor.BringToFront();
}
}
}
}

View file

@ -56,7 +56,7 @@ namespace ParquetViewer
this.exportFileDialog.FilterIndex = (int)defaultFileType + 1;
if (this._openParquetEngine?.Metadata.SchemaTree?.Children.All(s => s.IsPrimitive) == true
&& this._openParquetEngine is not Engine.DuckDB.ParquetEngine)
&& this._openParquetEngine is Engine.ParquetNET.ParquetEngine)
{
this.exportFileDialog.Filter += "|Parquet file (*.parquet)|*.parquet";
}
@ -189,9 +189,7 @@ namespace ParquetViewer
else if (selectedFileType == FileType.PARQUET)
{
ArgumentNullException.ThrowIfNull(engine);
var engineTypeName = engine is Engine.ParquetNET.ParquetEngine ? "ParquetNET" :
engine is Engine.DuckDB.ParquetEngine ? "DuckDB" :
"Unknown";
var engineTypeName = engine is Engine.ParquetNET.ParquetEngine ? "ParquetNET" : "DuckDB";
return WriteDataToParquetFile(engine, dataTable, filePath, cancellationToken, progress, engineTypeName);
}
else
@ -239,6 +237,7 @@ namespace ParquetViewer
string dateFormat = AppSettings.DateTimeDisplayFormat.GetDateFormat();
string dateOnlyFormat = AppSettings.DateTimeDisplayFormat.GetDateOnlyFormat();
string timeOnlyFormat = AppSettings.DateTimeDisplayFormat.GetTimeOnlyFormat();
foreach (DataRowView row in dataTable.DefaultView)
{
rowBuilder.Clear();
@ -268,6 +267,10 @@ namespace ParquetViewer
{
rowBuilder.Append(UtilityMethods.CleanCSVValue(dateOnly.ToString(dateOnlyFormat)));
}
else if (value is TimeOnly timeOnly)
{
rowBuilder.Append(UtilityMethods.CleanCSVValue(timeOnly.ToString(timeOnlyFormat)));
}
else
{
var stringValue = value!.ToString()!; //we never have `null` only `DBNull.Value`
@ -286,6 +289,7 @@ namespace ParquetViewer
{
string dateFormat = AppSettings.DateTimeDisplayFormat.GetDateFormat();
string dateOnlyFormat = AppSettings.DateTimeDisplayFormat.GetDateOnlyFormat();
string timeOnlyFormat = AppSettings.DateTimeDisplayFormat.GetTimeOnlyFormat();
using var fs = new FileStream(path, FileMode.OpenOrCreate);
var excelWriter = new ExcelWriter(fs);
excelWriter.BeginWrite();
@ -327,6 +331,10 @@ namespace ParquetViewer
{
excelWriter.WriteCell(i + 1, j, dateOnly.ToString(dateOnlyFormat));
}
else if (value is TimeOnly timeOnly)
{
excelWriter.WriteCell(i + 1, j, timeOnly.ToString(timeOnlyFormat));
}
else
{
var stringValue = value.ToString();

View file

@ -2,7 +2,6 @@ using ParquetViewer.Analytics;
using ParquetViewer.Controls;
using ParquetViewer.Engine;
using ParquetViewer.Engine.Exceptions;
using ParquetViewer.Exceptions;
using ParquetViewer.Helpers;
using System;
using System.Collections.Generic;
@ -51,7 +50,6 @@ namespace ParquetViewer
this.mainGridView.ClearQuickPeekForms();
this.mainGridView.ClearColumnFormatOverrides();
this.ResetGetSQLCreateTableScriptToolStripMenuItemToolTipText();
this._queryEditorSavedQueryText = null;
if (string.IsNullOrWhiteSpace(this._openFileOrFolderPath))
{
@ -284,6 +282,8 @@ namespace ParquetViewer
if (this._openParquetEngine is null)
return;
#if RELEASE_SELFCONTAINED
//Self contained release has both Parquet.NET and DuckDB engines included as the file size remains the same.
try
{
await this.LoadFileToGridviewImpl(this._openParquetEngine);
@ -298,14 +298,23 @@ namespace ParquetViewer
{
var duckDbEngine = await Engine.DuckDB.ParquetEngine.OpenFileOrFolderAsync(this.OpenFileOrFolderPath!, default);
await LoadFileToGridviewImpl(duckDbEngine);
this.SwapEngines(duckDbEngine);
SwapEngines(duckDbEngine);
}
catch (Exception duckDbEx)
{
//If DuckDB fails too, bail
throw new RowsReadException(unhandledEx, duckDbEx);
throw new Exceptions.RowsReadException(unhandledEx, duckDbEx);
}
}
void SwapEngines(IParquetEngine newEngine)
{
this._openParquetEngine.DisposeSafely();
this._openParquetEngine = newEngine;
}
#else
await this.LoadFileToGridviewImpl(this._openParquetEngine);
#endif
}
private async Task LoadFileToGridviewImpl(IParquetEngine engine)
@ -363,9 +372,9 @@ namespace ParquetViewer
{
HandleSomeFilesSkippedException(ex);
}
catch (Engine.Exceptions.FileReadException ex)
catch (FileReadException ex)
{
MainForm.HandleFileReadException(ex);
HandleFileReadException(ex);
}
catch (MultipleSchemasFoundException ex)
{
@ -402,9 +411,9 @@ namespace ParquetViewer
if (wasSuccessful)
{
var engineType = this._openParquetEngine is Engine.DuckDB.ParquetEngine
? FileOpenEvent.ParquetEngineTypeId.DuckDB
: FileOpenEvent.ParquetEngineTypeId.ParquetNET;
var engineType = this._openParquetEngine is Engine.ParquetNET.ParquetEngine
? FileOpenEvent.ParquetEngineTypeId.ParquetNET
: FileOpenEvent.ParquetEngineTypeId.DuckDB;
FileOpenEvent.FireAndForget(
Directory.Exists(this.OpenFileOrFolderPath),
@ -529,11 +538,5 @@ namespace ParquetViewer
this.englishToolStripMenuItem.Checked = true;
}
}
private void SwapEngines(IParquetEngine newEngine)
{
this._openParquetEngine.DisposeSafely();
this._openParquetEngine = newEngine;
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -41,7 +41,7 @@
<PublishSingleFile>true</PublishSingleFile>
<PublishSelfContained>true</PublishSelfContained>
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishReadyToRun>false</PublishReadyToRun>
</PropertyGroup>
<ItemGroup>
<Compile Update="Controls\DelayedOnChangedTextBox.cs">
@ -74,14 +74,16 @@
<ItemGroup>
<PackageReference Include="Apache.Arrow" />
<PackageReference Include="dotnet-file-associator" />
<PackageReference Include="FCTB" />
<PackageReference Include="MiniExcel" />
<PackageReference Include="NAudio" />
<PackageReference Include="NAudio.WinForms" />
<PackageReference Include="Parquet.Net" />
</ItemGroup>
<ItemGroup>
<ItemGroup Condition="'$(Configuration)' == 'Release_SelfContained'">
<!--We only use DuckDB in the selfcontained release to save on file size-->
<ProjectReference Include="..\ParquetViewer.Engine.DuckDB\ParquetViewer.Engine.DuckDB.csproj" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ParquetViewer.Engine.ParquetNET\ParquetViewer.Engine.ParquetNET.csproj" />
<ProjectReference Include="..\ParquetViewer.Engine\ParquetViewer.Engine.csproj" />
</ItemGroup>
@ -103,4 +105,4 @@
<LastGenOutput>Strings.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
</Project>
</Project>

View file

@ -21,4 +21,4 @@ using System.Runtime.Versioning;
// Minor Version
// Patch Version
// Revision
[assembly: AssemblyVersion("4.0.0.0")]
[assembly: AssemblyVersion("4.1.1.0")]

View file

@ -1,346 +0,0 @@
using FastColoredTextBoxNS;
using ParquetViewer.Controls;
using System.Windows.Forms;
namespace ParquetViewer
{
partial class QueryEditor
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(QueryEditor));
mainSplitContainer = new SplitContainer();
mainTableLayoutPanel = new TableLayoutPanel();
queryRichTextBox = new FastColoredTextBox();
queryEditorContextMenuStrip = new ContextMenuStrip(components);
copyTextMenuItem = new ToolStripMenuItem();
pasteTextMenuItem = new ToolStripMenuItem();
executeQueryButton = new Button();
querySyntaxDocsButton = new Button();
resultsGridView = new ParquetGridView();
statusStrip = new StatusStrip();
toolStripStatusLabel1 = new ToolStripStatusLabel();
showingCountLabel = new ToolStripStatusLabel();
toolStripStatusLabel2 = new ToolStripStatusLabel();
toolStripStatusLabel4 = new ToolStripStatusLabel();
zoomPercentageDropDown = new ToolStripDropDownButton();
percentage100 = new ToolStripMenuItem();
percentage110 = new ToolStripMenuItem();
percentage125 = new ToolStripMenuItem();
percentage140 = new ToolStripMenuItem();
percentage150 = new ToolStripMenuItem();
queryExecutionStatusLabel = new ToolStripStatusLabel();
timeElapsedLabel = new ToolStripStatusLabel();
closeButton = new Button();
executeQueryKeyboardShortcutToolTip = new ToolTip(components);
((System.ComponentModel.ISupportInitialize)mainSplitContainer).BeginInit();
mainSplitContainer.Panel1.SuspendLayout();
mainSplitContainer.Panel2.SuspendLayout();
mainSplitContainer.SuspendLayout();
mainTableLayoutPanel.SuspendLayout();
((System.ComponentModel.ISupportInitialize)queryRichTextBox).BeginInit();
queryEditorContextMenuStrip.SuspendLayout();
((System.ComponentModel.ISupportInitialize)resultsGridView).BeginInit();
statusStrip.SuspendLayout();
SuspendLayout();
//
// mainSplitContainer
//
resources.ApplyResources(mainSplitContainer, "mainSplitContainer");
mainSplitContainer.BackColor = System.Drawing.SystemColors.Control;
mainSplitContainer.BorderStyle = BorderStyle.FixedSingle;
mainSplitContainer.Name = "mainSplitContainer";
//
// mainSplitContainer.Panel1
//
resources.ApplyResources(mainSplitContainer.Panel1, "mainSplitContainer.Panel1");
mainSplitContainer.Panel1.Controls.Add(mainTableLayoutPanel);
executeQueryKeyboardShortcutToolTip.SetToolTip(mainSplitContainer.Panel1, resources.GetString("mainSplitContainer.Panel1.ToolTip"));
//
// mainSplitContainer.Panel2
//
resources.ApplyResources(mainSplitContainer.Panel2, "mainSplitContainer.Panel2");
mainSplitContainer.Panel2.BackColor = System.Drawing.SystemColors.Control;
mainSplitContainer.Panel2.Controls.Add(resultsGridView);
executeQueryKeyboardShortcutToolTip.SetToolTip(mainSplitContainer.Panel2, resources.GetString("mainSplitContainer.Panel2.ToolTip"));
executeQueryKeyboardShortcutToolTip.SetToolTip(mainSplitContainer, resources.GetString("mainSplitContainer.ToolTip"));
//
// mainTableLayoutPanel
//
resources.ApplyResources(mainTableLayoutPanel, "mainTableLayoutPanel");
mainTableLayoutPanel.Controls.Add(queryRichTextBox, 0, 0);
mainTableLayoutPanel.Controls.Add(executeQueryButton, 0, 1);
mainTableLayoutPanel.Controls.Add(querySyntaxDocsButton, 1, 1);
mainTableLayoutPanel.Name = "mainTableLayoutPanel";
executeQueryKeyboardShortcutToolTip.SetToolTip(mainTableLayoutPanel, resources.GetString("mainTableLayoutPanel.ToolTip"));
//
// queryRichTextBox
//
resources.ApplyResources(queryRichTextBox, "queryRichTextBox");
queryRichTextBox.AutoCompleteBracketsList = new char[]
{
'(',
')',
'{',
'}',
'[',
']',
'"',
'"',
'\'',
'\''
};
queryRichTextBox.AutoIndentCharsPatterns = "";
queryRichTextBox.BackBrush = null;
queryRichTextBox.CharHeight = 16;
queryRichTextBox.CharWidth = 9;
mainTableLayoutPanel.SetColumnSpan(queryRichTextBox, 2);
queryRichTextBox.CommentPrefix = "--";
queryRichTextBox.ContextMenuStrip = queryEditorContextMenuStrip;
queryRichTextBox.DisabledColor = System.Drawing.Color.FromArgb(100, 180, 180, 180);
queryRichTextBox.Hotkeys = resources.GetString("queryRichTextBox.Hotkeys");
queryRichTextBox.IsReplaceMode = false;
queryRichTextBox.Language = Language.SQL;
queryRichTextBox.LeftBracket = '(';
queryRichTextBox.Name = "queryRichTextBox";
queryRichTextBox.Paddings = new Padding(0);
queryRichTextBox.RightBracket = ')';
queryRichTextBox.SelectionColor = System.Drawing.Color.FromArgb(60, 0, 0, 255);
queryRichTextBox.ServiceColors = (ServiceColors)resources.GetObject("queryRichTextBox.ServiceColors");
executeQueryKeyboardShortcutToolTip.SetToolTip(queryRichTextBox, resources.GetString("queryRichTextBox.ToolTip"));
queryRichTextBox.Zoom = 100;
queryRichTextBox.TextChanged += queryRichTextBox_TextChanged;
queryRichTextBox.KeyDown += queryRichTextBox_KeyDown;
//
// queryEditorContextMenuStrip
//
resources.ApplyResources(queryEditorContextMenuStrip, "queryEditorContextMenuStrip");
queryEditorContextMenuStrip.Items.AddRange(new ToolStripItem[] { copyTextMenuItem, pasteTextMenuItem });
queryEditorContextMenuStrip.Name = "queryEditorContextMenuStrip";
executeQueryKeyboardShortcutToolTip.SetToolTip(queryEditorContextMenuStrip, resources.GetString("queryEditorContextMenuStrip.ToolTip"));
//
// copyTextMenuItem
//
resources.ApplyResources(copyTextMenuItem, "copyTextMenuItem");
copyTextMenuItem.Name = "copyTextMenuItem";
copyTextMenuItem.Click += copyTextMenuItem_Click;
//
// pasteTextMenuItem
//
resources.ApplyResources(pasteTextMenuItem, "pasteTextMenuItem");
pasteTextMenuItem.Image = Resources.Icons.paste_icon_24x24;
pasteTextMenuItem.Name = "pasteTextMenuItem";
pasteTextMenuItem.Click += pasteTextMenuItem_Click;
//
// executeQueryButton
//
resources.ApplyResources(executeQueryButton, "executeQueryButton");
executeQueryButton.Image = Resources.Icons.exclamation_icon;
executeQueryButton.Name = "executeQueryButton";
executeQueryKeyboardShortcutToolTip.SetToolTip(executeQueryButton, resources.GetString("executeQueryButton.ToolTip"));
executeQueryButton.UseVisualStyleBackColor = true;
executeQueryButton.Click += executeQueryButton_Click;
//
// querySyntaxDocsButton
//
resources.ApplyResources(querySyntaxDocsButton, "querySyntaxDocsButton");
querySyntaxDocsButton.Image = Resources.Icons.external_link_icon;
querySyntaxDocsButton.Name = "querySyntaxDocsButton";
executeQueryKeyboardShortcutToolTip.SetToolTip(querySyntaxDocsButton, resources.GetString("querySyntaxDocsButton.ToolTip"));
querySyntaxDocsButton.UseVisualStyleBackColor = true;
querySyntaxDocsButton.Click += querySyntaxDocsButton_Click;
//
// resultsGridView
//
resources.ApplyResources(resultsGridView, "resultsGridView");
resultsGridView.AllowUserToAddRows = false;
resultsGridView.AllowUserToDeleteRows = false;
resultsGridView.AllowUserToOrderColumns = true;
resultsGridView.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithoutHeaderText;
resultsGridView.ColumnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single;
resultsGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize;
resultsGridView.ColumnNameEscapeFormat = "[{0}]";
resultsGridView.CopyAsWhereIcon = null;
resultsGridView.CopyToClipboardIcon = null;
resultsGridView.DateValueEscapeFormat = "#{0}#";
resultsGridView.EnableHeadersVisualStyles = false;
resultsGridView.Name = "resultsGridView";
resultsGridView.ReadOnly = true;
resultsGridView.ShowCellToolTips = false;
resultsGridView.ShowCopyAsWhereContextMenuItem = false;
executeQueryKeyboardShortcutToolTip.SetToolTip(resultsGridView, resources.GetString("resultsGridView.ToolTip"));
//
// statusStrip
//
resources.ApplyResources(statusStrip, "statusStrip");
statusStrip.Items.AddRange(new ToolStripItem[] { toolStripStatusLabel1, showingCountLabel, toolStripStatusLabel2, toolStripStatusLabel4, zoomPercentageDropDown, queryExecutionStatusLabel, timeElapsedLabel });
statusStrip.Name = "statusStrip";
executeQueryKeyboardShortcutToolTip.SetToolTip(statusStrip, resources.GetString("statusStrip.ToolTip"));
//
// toolStripStatusLabel1
//
resources.ApplyResources(toolStripStatusLabel1, "toolStripStatusLabel1");
toolStripStatusLabel1.Name = "toolStripStatusLabel1";
//
// showingCountLabel
//
resources.ApplyResources(showingCountLabel, "showingCountLabel");
showingCountLabel.Name = "showingCountLabel";
//
// toolStripStatusLabel2
//
resources.ApplyResources(toolStripStatusLabel2, "toolStripStatusLabel2");
toolStripStatusLabel2.Name = "toolStripStatusLabel2";
//
// toolStripStatusLabel4
//
resources.ApplyResources(toolStripStatusLabel4, "toolStripStatusLabel4");
toolStripStatusLabel4.Name = "toolStripStatusLabel4";
toolStripStatusLabel4.Spring = true;
//
// zoomPercentageDropDown
//
resources.ApplyResources(zoomPercentageDropDown, "zoomPercentageDropDown");
zoomPercentageDropDown.DisplayStyle = ToolStripItemDisplayStyle.Text;
zoomPercentageDropDown.DropDownItems.AddRange(new ToolStripItem[] { percentage100, percentage110, percentage125, percentage140, percentage150 });
zoomPercentageDropDown.Name = "zoomPercentageDropDown";
//
// percentage100
//
resources.ApplyResources(percentage100, "percentage100");
percentage100.Checked = true;
percentage100.CheckOnClick = true;
percentage100.CheckState = CheckState.Checked;
percentage100.Name = "percentage100";
percentage100.Tag = "100";
percentage100.Click += zoomPercentage_Click;
//
// percentage110
//
resources.ApplyResources(percentage110, "percentage110");
percentage110.Name = "percentage110";
percentage110.Tag = "110";
percentage110.Click += zoomPercentage_Click;
//
// percentage125
//
resources.ApplyResources(percentage125, "percentage125");
percentage125.CheckOnClick = true;
percentage125.Name = "percentage125";
percentage125.Tag = "125";
percentage125.Click += zoomPercentage_Click;
//
// percentage140
//
resources.ApplyResources(percentage140, "percentage140");
percentage140.Name = "percentage140";
percentage140.Tag = "140";
percentage140.Click += zoomPercentage_Click;
//
// percentage150
//
resources.ApplyResources(percentage150, "percentage150");
percentage150.CheckOnClick = true;
percentage150.Name = "percentage150";
percentage150.Tag = "150";
percentage150.Click += zoomPercentage_Click;
//
// queryExecutionStatusLabel
//
resources.ApplyResources(queryExecutionStatusLabel, "queryExecutionStatusLabel");
queryExecutionStatusLabel.Name = "queryExecutionStatusLabel";
//
// timeElapsedLabel
//
resources.ApplyResources(timeElapsedLabel, "timeElapsedLabel");
timeElapsedLabel.Name = "timeElapsedLabel";
//
// closeButton
//
resources.ApplyResources(closeButton, "closeButton");
closeButton.Name = "closeButton";
executeQueryKeyboardShortcutToolTip.SetToolTip(closeButton, resources.GetString("closeButton.ToolTip"));
closeButton.UseVisualStyleBackColor = true;
closeButton.Click += closeButton_Click;
//
// QueryEditor
//
AcceptButton = executeQueryButton;
resources.ApplyResources(this, "$this");
AutoScaleMode = AutoScaleMode.Font;
CancelButton = closeButton;
Controls.Add(closeButton);
Controls.Add(mainSplitContainer);
Controls.Add(statusStrip);
Icon = Resources.Icons.sql_server_icon;
Name = "QueryEditor";
executeQueryKeyboardShortcutToolTip.SetToolTip(this, resources.GetString("$this.ToolTip"));
Load += QueryEditor_Load;
KeyUp += QueryEditor_KeyUp;
mainSplitContainer.Panel1.ResumeLayout(false);
mainSplitContainer.Panel2.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)mainSplitContainer).EndInit();
mainSplitContainer.ResumeLayout(false);
mainTableLayoutPanel.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)queryRichTextBox).EndInit();
queryEditorContextMenuStrip.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)resultsGridView).EndInit();
statusStrip.ResumeLayout(false);
statusStrip.PerformLayout();
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.TableLayoutPanel mainTableLayoutPanel;
private FastColoredTextBox queryRichTextBox;
private System.Windows.Forms.Button executeQueryButton;
private System.Windows.Forms.StatusStrip statusStrip;
private Controls.ParquetGridView resultsGridView;
private ToolStripStatusLabel toolStripStatusLabel1;
private ToolStripStatusLabel showingCountLabel;
private ToolStripStatusLabel toolStripStatusLabel2;
private ToolStripStatusLabel queryExecutionStatusLabel;
private ToolStripStatusLabel timeElapsedLabel;
private SplitContainer mainSplitContainer;
private ToolStripDropDownButton zoomPercentageDropDown;
private ToolStripMenuItem percentage100;
private ToolStripMenuItem percentage125;
private ToolStripMenuItem percentage150;
private ToolStripStatusLabel toolStripStatusLabel4;
private ToolStripMenuItem percentage110;
private ToolStripMenuItem percentage140;
private Button querySyntaxDocsButton;
private Button closeButton;
private ToolTip executeQueryKeyboardShortcutToolTip;
private ContextMenuStrip queryEditorContextMenuStrip;
private ToolStripMenuItem copyTextMenuItem;
private ToolStripMenuItem pasteTextMenuItem;
}
}

View file

@ -1,460 +0,0 @@
using DuckDB.NET.Data;
using ParquetViewer.Analytics;
using ParquetViewer.Controls;
using ParquetViewer.Engine;
using ParquetViewer.Engine.Exceptions;
using ParquetViewer.Engine.Types;
using ParquetViewer.Helpers;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace ParquetViewer
{
public partial class QueryEditor : FormBase
{
private const string QUERY_FORMAT =
@"SELECT {0}
FROM {1}
LIMIT {2}
OFFSET {3} ";
private Brush _splitterColor = Brushes.Silver;
private bool _wasByteArrayConversionErrorShown = false;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public string QueryText
{
get => this.queryRichTextBox.Text;
set => this.queryRichTextBox.Text = value;
}
public QueryEditor()
{
InitializeComponent();
this.mainSplitContainer.Paint += MainSplitContainer_Paint;
this.resultsGridView.ShowCopyAsWhereContextMenuItem = true;
this.resultsGridView.CopyAsWhereIcon = Resources.Icons.sql_server_icon.ToBitmap();
this.resultsGridView.ColumnNameEscapeFormat = "\"{0}\"";
this.resultsGridView.DateValueEscapeFormat = "'{0}'";
}
public QueryEditor(IEnumerable<string>? fields = null, string? filePath = null, int offset = 0, int limit = 1000) : this()
{
var filePathSpecified = filePath is not null;
filePath ??= Path.Combine(Path.GetDirectoryName(Application.ExecutablePath) ?? string.Empty, "your-file.parquet");
var queryFields = fields is not null ? string.Join(',', fields.Select(f => $"\"{f}\"")) : "*";
var fromClause = filePath?.EndsWith(".parquet") == true ? $"'{filePath}'" : $"read_parquet('{filePath}')";
this.queryRichTextBox.Text = QUERY_FORMAT.Format(queryFields, fromClause, limit, offset);
if (!filePathSpecified)
this.executeQueryButton.Enabled = false; //start off disabled, so the user has to adjust the query
}
private void QueryEditor_Load(object sender, EventArgs e)
{
this.resultsGridView.AutoGenerateColumns = true;
this.queryExecutionStatusLabel.Visible = false;
this.timeElapsedLabel.Visible = false;
//Set caret to the end of the text
this.queryRichTextBox.SelectionStart = this.queryRichTextBox.Text.Length;
this.queryRichTextBox.SelectionLength = 0;
SetZoom(AppSettings.QueryEditorZoomLevel);
}
private async void executeQueryButton_Click(object sender, EventArgs e)
{
this.executeQueryButton.Enabled = false;
this.Cursor = Cursors.WaitCursor;
this.queryExecutionStatusLabel.Visible = true;
this.timeElapsedLabel.Visible = true;
this.queryExecutionStatusLabel.Text = Resources.Strings.QueryRunningStatusText;
this.timeElapsedLabel.Text = "00:00";
this.resultsGridView.Enabled = false;
var result = new DataTable();
var queryEvent = new ExecuteQueryEvent() { IsDuckDB = true };
try
{
var stopwatch = Stopwatch.StartNew();
var query = this.queryRichTextBox.Text;
var queryTask = Task.Run(() =>
{
using var connection = new DuckDBConnection("Data Source=:memory:");
connection.Open();
using var command = connection.CreateCommand();
command.CommandText = query;
using var reader = command.ExecuteReader();
result.Load(reader);
});
while (!queryTask.IsCompleted)
{
await Task.Delay(100);
this.timeElapsedLabel.Text = stopwatch.Elapsed.ToString("mm\\:ss");
}
stopwatch.Stop();
await queryTask;
this.queryExecutionStatusLabel.Text = Resources.Strings.QueryFinishedStatusText;
this.timeElapsedLabel.Text = stopwatch.Elapsed.ToString("mm\\:ss");
queryEvent.IsValid = true;
queryEvent.RunTimeMS = stopwatch.ElapsedMilliseconds;
queryEvent.RecordCountFiltered = result.Rows.Count;
queryEvent.ColumnCount = result.Columns.Count;
}
catch (Exception ex)
{
result.Dispose();
if (ex is InvalidCastException && ex.Message.Contains("The list contains null value"))
{
MessageBox.Show(Resources.Errors.ListsWithNullsErrorMessage, Resources.Errors.ListsWithNullsErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else if (ex is DuckDBException && ex.Message.StartsWith("Parser Error:"))
{
MessageBox.Show($"{Resources.Errors.InvalidQueryErrorMessage}{Environment.NewLine}{Environment.NewLine}{ex.Message}",
Resources.Errors.InvalidQueryErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else if (ex is OverflowException && ex.Message.Contains("Value was either too large or too small for a Decimal"))
{
MessageBox.Show(Resources.Errors.DecimalValueUnknownSizeTooLargeErrorMessageFormat
.Format(null, null, null,
DecimalOverflowException.MAX_DECIMAL_PRECISION,
DecimalOverflowException.MAX_DECIMAL_SCALE),
Resources.Errors.DecimalValueTooLargeErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
ExceptionEvent.FireAndForget(ex);
MessageBox.Show(ex.Message, Resources.Errors.QueryExecutionErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
this.executeQueryButton.Enabled = true;
this.resultsGridView.Enabled = true;
this.Cursor = Cursors.Default;
return;
}
finally
{
//Fire and forget
var _ = queryEvent.Record();
}
//Cleanup previous results
if (this.resultsGridView.DataSource is DataTable dt)
{
dt.Dispose();
}
try
{
this.resultsGridView.DataSource = ConvertValues(result);
this.showingCountLabel.Text = result.Rows.Count.ToString();
}
catch (Exception ex)
{
ExceptionEvent.FireAndForget(ex);
MessageBox.Show($"{ex.Message}{Environment.NewLine}{Environment.NewLine}{ex.StackTrace}",
Resources.Errors.RenderResultsErrorTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
this.executeQueryButton.Enabled = true;
this.resultsGridView.Enabled = true;
this.Cursor = Cursors.Default;
}
}
private void queryRichTextBox_TextChanged(object sender, FastColoredTextBoxNS.TextChangedEventArgs e)
{
this.executeQueryButton.Enabled = true;
}
private void zoomPercentage_Click(object sender, EventArgs e)
{
if (sender is ToolStripMenuItem menuItem && int.TryParse(menuItem.Tag?.ToString(), out int zoomPercentage))
{
SetZoom(zoomPercentage);
}
}
private void SetZoom(int? zoomPercentage)
{
zoomPercentage = Math.Clamp(zoomPercentage ?? 100, 100, 150);
this.queryRichTextBox.Zoom = zoomPercentage.Value;
this.zoomPercentageDropDown.Text = Resources.Strings.QueryZoomStatusTextFormat.Format(zoomPercentage);
AppSettings.QueryEditorZoomLevel = zoomPercentage.Value;
foreach (ToolStripMenuItem menuItem in this.zoomPercentageDropDown.DropDownItems)
{
menuItem.Checked = int.TryParse(menuItem.Tag?.ToString(), out int percentage) && percentage == zoomPercentage.Value;
}
}
private void querySyntaxDocsButton_Click(object sender, EventArgs e)
{
Process.Start(new ProcessStartInfo(Constants.DuckDBSqlSyntaxURL) { UseShellExecute = true });
}
private void queryRichTextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F5 || (e.Shift && e.KeyCode == Keys.Enter))
{
executeQueryButton.PerformClick();
e.Handled = true;
e.SuppressKeyPress = true;
}
}
private void QueryEditor_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyValue == (int)Keys.Escape)
{
this.Close();
e.Handled = true;
}
}
private void closeButton_Click(object sender, EventArgs e)
{
this.Close();
}
private void MainSplitContainer_Paint(object? sender, PaintEventArgs e)
{
//Draw a line where the splitter is so users can tell they can resize the sections
var splitContainer = sender as SplitContainer;
if (splitContainer != null)
{
var rectangle = splitContainer.SplitterRectangle;
rectangle.Offset(0, 1);
rectangle.Height -= 2;
e.Graphics.FillRectangle(_splitterColor, rectangle);
}
}
private DataTable ConvertValues(DataTable intermediateResult)
{
var hasComplexType = false;
foreach (DataColumn column in intermediateResult.Columns)
{
if (column.DataType.ImplementsInterface<IDictionary>()
|| column.DataType.ImplementsInterface<IList>()
|| column.DataType == typeof(Stream))
{
hasComplexType = true;
break;
}
}
if (!hasComplexType)
{
//Nothing to convert
return intermediateResult;
}
var result = new DataTable();
foreach (DataColumn column in intermediateResult.Columns)
{
if (column.DataType == typeof(Dictionary<string, object?>))
{
result.Columns.Add(new DataColumn(column.ColumnName, typeof(StructValue)));
}
else if (column.DataType.ImplementsInterface<IList>())
{
result.Columns.Add(new DataColumn(column.ColumnName, typeof(ListValue)));
}
else if (column.DataType.ImplementsInterface<IDictionary>())
{
result.Columns.Add(new DataColumn(column.ColumnName, typeof(MapValue)));
}
else if (column.DataType == typeof(Stream))
{
result.Columns.Add(new DataColumn(column.ColumnName, typeof(ByteArrayValue)));
}
else
{
result.Columns.Add(new DataColumn(column.ColumnName, column.DataType));
}
}
result.BeginLoadData();
foreach (DataRow row in intermediateResult.Rows)
{
var newRow = result.NewRow();
for (var i = 0; i < row.ItemArray.Length; i++)
{
var value = row.ItemArray[i];
newRow[i] = ConvertValue(value!);
}
result.Rows.Add(newRow);
}
result.EndLoadData();
return result;
}
private object ConvertValue(object? value)
{
if (value == DBNull.Value || value is null)
{
return DBNull.Value;
}
else if (value is Dictionary<string, object?> structDictionary)
{
var dataRow = new QueryResultDataRow(structDictionary.Keys.ToList(),
structDictionary.Values.Select(ConvertValue).ToArray());
var structValue = new StructValue(dataRow);
return structValue;
}
else if (value is IList list)
{
var arrayList = new ArrayList(list.Count);
var listType = typeof(object);
for (var i = 0; i < list.Count; i++)
{
var convertedListValue = ConvertValue(list[i]);
arrayList.Add(convertedListValue);
if (convertedListValue != DBNull.Value)
{
listType = convertedListValue.GetType();
}
}
var listValue = new ListValue(arrayList, listType);
return listValue;
}
else if (value is IDictionary dictionary)
{
var keysList = new ArrayList(dictionary.Keys.Count);
var valuesList = new ArrayList(dictionary.Values.Count);
var keysType = typeof(object);
var valuesType = typeof(object);
foreach (var keyValuePair in Engine.Helpers.PairEnumerables(
dictionary.Keys.OfType<object?>(),
dictionary.Values.OfType<object?>(),
DBNull.Value))
{
var convertedKey = ConvertValue(keyValuePair.Item1);
var convertedValue = ConvertValue(keyValuePair.Item2);
keysList.Add(convertedKey);
valuesList.Add(convertedValue);
if (convertedKey != DBNull.Value)
{
keysType = convertedKey.GetType();
}
if (convertedValue != DBNull.Value)
{
valuesType = convertedValue.GetType();
}
}
var mapValue = new MapValue(
keysList, keysType,
valuesList, valuesType);
return mapValue;
}
else if (value is Stream byteArray)
{
//DuckDB doesn't seem to like byte array values. It fails to read after the first row with a memory access violation error.
if (!this._wasByteArrayConversionErrorShown)
{
this._wasByteArrayConversionErrorShown = true;
MessageBox.Show(
Resources.Strings.ByteArraysNotSupportedErrorMessage,
Resources.Strings.ByteArraysNotSupportedErrorTitle,
MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
return DBNull.Value;
/*
using var ms = new MemoryStream();
byteArray.CopyTo(ms); //MemoryAccessViolation thrown here on second row and beyond
var byteArrayValue = new ByteArrayValue(ms.ToArray());
return byteArrayValue;
*/
}
else
{
return value;
}
}
private class QueryResultDataRow : IDataRowLite
{
public IReadOnlyCollection<string> ColumnNames { get; }
public object[] Row { get; }
public QueryResultDataRow(List<string> columnNames, object[] data)
{
this.ColumnNames = columnNames.AsReadOnly();
this.Row = data;
}
public object GetValue(string columnName)
{
var result = this.ColumnNames.Index().Where(pair => pair.Item == columnName).FirstOrDefault();
if (result == default)
throw new ArgumentOutOfRangeException($"Column `{columnName}` doesn't exist");
return this.Row[result.Index];
}
}
public override void SetTheme(Theme theme)
{
if (DesignMode)
{
return;
}
base.SetTheme(theme);
this.resultsGridView.GridTheme = theme;
this.querySyntaxDocsButton.ForeColor = Color.Black;
this.executeQueryButton.ForeColor = Color.Black;
this.statusStrip.BackColor = theme.FormBackgroundColor;
this.statusStrip.ForeColor = theme.TextColor;
this.mainTableLayoutPanel.BackColor = theme.FormBackgroundColor;
this._splitterColor = new SolidBrush(theme.DisabledTextColor);
this.queryRichTextBox.IndentBackColor = theme.RowHeaderColor;
this.queryRichTextBox.ForeColor = theme.TextColor;
this.queryRichTextBox.SelectionColor = theme.SelectionBackColor;
this.queryRichTextBox.CaretColor = theme.TextColor;
if (theme == Theme.LightModeTheme)
{
this.queryRichTextBox.BackColor = Color.White;
}
else
{
this.queryRichTextBox.BackColor = theme.CellBackgroundColor;
}
this.statusStrip.Renderer = theme.ToolStripRenderer;
}
private void copyTextMenuItem_Click(object sender, EventArgs e)
{
this.queryRichTextBox.Copy();
}
private void pasteTextMenuItem_Click(object sender, EventArgs e)
{
this.queryRichTextBox.Paste();
}
}
}

View file

@ -1,690 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="&gt;&gt;mainSplitContainer.Panel1.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="&gt;&gt;percentage110.Name" xml:space="preserve">
<value>percentage110</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="mainTableLayoutPanel.LayoutSettings" type="System.Windows.Forms.TableLayoutSettings, System.Windows.Forms">
<value>&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;TableLayoutSettings&gt;&lt;Controls&gt;&lt;Control Name="queryRichTextBox" Row="0" RowSpan="1" Column="0" ColumnSpan="2" /&gt;&lt;Control Name="executeQueryButton" Row="1" RowSpan="1" Column="0" ColumnSpan="1" /&gt;&lt;Control Name="querySyntaxDocsButton" Row="1" RowSpan="1" Column="1" ColumnSpan="1" /&gt;&lt;/Controls&gt;&lt;Columns Styles="Percent,100,Absolute,130" /&gt;&lt;Rows Styles="Percent,100,Absolute,32" /&gt;&lt;/TableLayoutSettings&gt;</value>
</data>
<data name="&gt;&gt;percentage150.Name" xml:space="preserve">
<value>percentage150</value>
</data>
<assembly alias="mscorlib" name="mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="mainSplitContainer.SplitterWidth" type="System.Int32, mscorlib">
<value>6</value>
</data>
<data name="queryRichTextBox.ToolTip" xml:space="preserve">
<value />
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="percentage150.Size" type="System.Drawing.Size, System.Drawing">
<value>102, 22</value>
</data>
<data name="closeButton.Location" type="System.Drawing.Point, System.Drawing">
<value>942, 221</value>
</data>
<data name="mainSplitContainer.ToolTip" xml:space="preserve">
<value />
</data>
<data name="&gt;&gt;executeQueryButton.Parent" xml:space="preserve">
<value>mainTableLayoutPanel</value>
</data>
<data name="&gt;&gt;percentage150.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;closeButton.Name" xml:space="preserve">
<value>closeButton</value>
</data>
<data name="querySyntaxDocsButton.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="&gt;&gt;percentage125.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;copyTextMenuItem.Name" xml:space="preserve">
<value>copyTextMenuItem</value>
</data>
<data name="mainSplitContainer.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="queryRichTextBox.Size" type="System.Drawing.Size, System.Drawing">
<value>973, 108</value>
</data>
<data name="&gt;&gt;querySyntaxDocsButton.Name" xml:space="preserve">
<value>querySyntaxDocsButton</value>
</data>
<data name="&gt;&gt;querySyntaxDocsButton.Parent" xml:space="preserve">
<value>mainTableLayoutPanel</value>
</data>
<data name="percentage150.Text" xml:space="preserve">
<value>150%</value>
</data>
<data name="mainSplitContainer.Size" type="System.Drawing.Size, System.Drawing">
<value>981, 368</value>
</data>
<data name="&gt;&gt;queryExecutionStatusLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="statusStrip.ToolTip" xml:space="preserve">
<value />
</data>
<data name="queryRichTextBox.Hotkeys" xml:space="preserve">
<value>Tab=IndentIncrease, Escape=ClearHints, PgUp=GoPageUp, PgDn=GoPageDown, End=GoEnd, Home=GoHome, Left=GoLeft, Up=GoUp, Right=GoRight, Down=GoDown, Insert=ReplaceMode, Del=DeleteCharRight, F3=FindNext, Shift+Tab=IndentDecrease, Shift+PgUp=GoPageUpWithSelection, Shift+PgDn=GoPageDownWithSelection, Shift+End=GoEndWithSelection, Shift+Home=GoHomeWithSelection, Shift+Left=GoLeftWithSelection, Shift+Up=GoUpWithSelection, Shift+Right=GoRightWithSelection, Shift+Down=GoDownWithSelection, Shift+Insert=Paste, Shift+Del=Cut, Ctrl+Back=ClearWordLeft, Ctrl+Space=AutocompleteMenu, Ctrl+End=GoLastLine, Ctrl+Home=GoFirstLine, Ctrl+Left=GoWordLeft, Ctrl+Up=ScrollUp, Ctrl+Right=GoWordRight, Ctrl+Down=ScrollDown, Ctrl+Insert=Copy, Ctrl+Del=ClearWordRight, Ctrl+0=ZoomNormal, Ctrl+A=SelectAll, Ctrl+B=BookmarkLine, Ctrl+C=Copy, Ctrl+E=MacroExecute, Ctrl+F=FindDialog, Ctrl+G=GoToDialog, Ctrl+H=ReplaceDialog, Ctrl+I=AutoIndentChars, Ctrl+M=MacroRecord, Ctrl+N=GoNextBookmark, Ctrl+R=Redo, Ctrl+U=UpperCase, Ctrl+V=Paste, Ctrl+X=Cut, Ctrl+Z=Undo, Ctrl+Add=ZoomIn, Ctrl+Subtract=ZoomOut, Ctrl+OemMinus=NavigateBackward, Ctrl+Shift+End=GoLastLineWithSelection, Ctrl+Shift+Home=GoFirstLineWithSelection, Ctrl+Shift+Left=GoWordLeftWithSelection, Ctrl+Shift+Right=GoWordRightWithSelection, Ctrl+Shift+B=UnbookmarkLine, Ctrl+Shift+C=CommentSelected, Ctrl+Shift+N=GoPrevBookmark, Ctrl+Shift+U=LowerCase, Ctrl+Shift+OemMinus=NavigateForward, Alt+Back=Undo, Alt+Up=MoveSelectedLinesUp, Alt+Down=MoveSelectedLinesDown, Alt+F=FindChar, Alt+Shift+Left=GoLeft_ColumnSelectionMode, Alt+Shift+Up=GoUp_ColumnSelectionMode, Alt+Shift+Right=GoRight_ColumnSelectionMode, Alt+Shift+Down=GoDown_ColumnSelectionMode</value>
</data>
<data name="resultsGridView.TabIndex" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="executeQueryButton.Size" type="System.Drawing.Size, System.Drawing">
<value>843, 26</value>
</data>
<data name="&gt;&gt;queryExecutionStatusLabel.Name" xml:space="preserve">
<value>queryExecutionStatusLabel</value>
</data>
<data name="resultsGridView.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 0</value>
</data>
<data name="toolStripStatusLabel2.Size" type="System.Drawing.Size, System.Drawing">
<value>44, 17</value>
</data>
<data name="timeElapsedLabel.Text" xml:space="preserve">
<value>00:00</value>
</data>
<data name="&gt;&gt;mainSplitContainer.Panel2.Type" xml:space="preserve">
<value>System.Windows.Forms.SplitterPanel, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="mainTableLayoutPanel.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 0</value>
</data>
<data name="&gt;&gt;statusStrip.Name" xml:space="preserve">
<value>statusStrip</value>
</data>
<data name="&gt;&gt;toolStripStatusLabel4.Name" xml:space="preserve">
<value>toolStripStatusLabel4</value>
</data>
<data name="&gt;&gt;statusStrip.Type" xml:space="preserve">
<value>System.Windows.Forms.StatusStrip, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;querySyntaxDocsButton.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="querySyntaxDocsButton.Text" xml:space="preserve">
<value>Query Syntax</value>
</data>
<data name="percentage125.Text" xml:space="preserve">
<value>125%</value>
</data>
<data name="&gt;&gt;timeElapsedLabel.Name" xml:space="preserve">
<value>timeElapsedLabel</value>
</data>
<data name="executeQueryButton.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 117</value>
</data>
<data name="&gt;&gt;pasteTextMenuItem.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;percentage100.Name" xml:space="preserve">
<value>percentage100</value>
</data>
<data name="resultsGridView.Size" type="System.Drawing.Size, System.Drawing">
<value>979, 212</value>
</data>
<data name="&gt;&gt;showingCountLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;resultsGridView.Parent" xml:space="preserve">
<value>mainSplitContainer.Panel2</value>
</data>
<data name="statusStrip.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="&gt;&gt;$this.Type" xml:space="preserve">
<value>ParquetViewer.Controls.FormBase, ParquetViewer, Culture=neutral, PublicKeyToken=null</value>
</data>
<data name="&gt;&gt;mainSplitContainer.Panel1.Parent" xml:space="preserve">
<value>mainSplitContainer</value>
</data>
<data name="&gt;&gt;copyTextMenuItem.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="$this.AutoScaleDimensions" type="System.Drawing.SizeF, System.Drawing">
<value>7, 15</value>
</data>
<data name="$this.MinimumSize" type="System.Drawing.Size, System.Drawing">
<value>490, 340</value>
</data>
<data name="percentage110.Text" xml:space="preserve">
<value>110%</value>
</data>
<data name="timeElapsedLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Segoe UI, 9pt, style=Bold</value>
</data>
<data name="&gt;&gt;statusStrip.ZOrder" xml:space="preserve">
<value>3</value>
</data>
<data name="&gt;&gt;mainSplitContainer.Panel2.Parent" xml:space="preserve">
<value>mainSplitContainer</value>
</data>
<data name="&gt;&gt;zoomPercentageDropDown.Name" xml:space="preserve">
<value>zoomPercentageDropDown</value>
</data>
<data name="percentage100.Size" type="System.Drawing.Size, System.Drawing">
<value>102, 22</value>
</data>
<data name="queryRichTextBox.Location" type="System.Drawing.Point, System.Drawing">
<value>3, 3</value>
</data>
<data name="&gt;&gt;mainSplitContainer.Panel1.Name" xml:space="preserve">
<value>mainSplitContainer.Panel1</value>
</data>
<data name="statusStrip.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 368</value>
</data>
<data name="mainTableLayoutPanel.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="&gt;&gt;executeQueryKeyboardShortcutToolTip.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolTip, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;mainTableLayoutPanel.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="&gt;&gt;queryEditorContextMenuStrip.Name" xml:space="preserve">
<value>queryEditorContextMenuStrip</value>
</data>
<data name="executeQueryButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Bottom, Left, Right</value>
</data>
<data name="&gt;&gt;queryRichTextBox.Parent" xml:space="preserve">
<value>mainTableLayoutPanel</value>
</data>
<data name="percentage140.Size" type="System.Drawing.Size, System.Drawing">
<value>102, 22</value>
</data>
<data name="mainSplitContainer.Panel1.ToolTip" xml:space="preserve">
<value />
</data>
<data name="&gt;&gt;zoomPercentageDropDown.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripDropDownButton, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;mainSplitContainer.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="toolStripStatusLabel4.Size" type="System.Drawing.Size, System.Drawing">
<value>638, 17</value>
</data>
<data name="zoomPercentageDropDown.ImageTransparentColor" type="System.Drawing.Color, System.Drawing">
<value>Magenta</value>
</data>
<data name="mainSplitContainer.Location" type="System.Drawing.Point, System.Drawing">
<value>0, 0</value>
</data>
<data name="&gt;&gt;executeQueryKeyboardShortcutToolTip.Name" xml:space="preserve">
<value>executeQueryKeyboardShortcutToolTip</value>
</data>
<data name="resultsGridView.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="executeQueryButton.Text" xml:space="preserve">
<value>Execute</value>
</data>
<data name="queryExecutionStatusLabel.Text" xml:space="preserve">
<value>Running:</value>
</data>
<data name="$this.ToolTip" xml:space="preserve">
<value />
</data>
<data name="&gt;&gt;toolStripStatusLabel1.Name" xml:space="preserve">
<value>toolStripStatusLabel1</value>
</data>
<data name="&gt;&gt;mainTableLayoutPanel.Name" xml:space="preserve">
<value>mainTableLayoutPanel</value>
</data>
<data name="&gt;&gt;toolStripStatusLabel4.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="$this.Text" xml:space="preserve">
<value>ParquetViewer - Query Editor (Powered by DuckDB)</value>
</data>
<data name="&gt;&gt;queryRichTextBox.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="percentage110.Size" type="System.Drawing.Size, System.Drawing">
<value>102, 22</value>
</data>
<data name="queryEditorContextMenuStrip.Size" type="System.Drawing.Size, System.Drawing">
<value>103, 48</value>
</data>
<data name="mainSplitContainer.Panel1MinSize" type="System.Int32, mscorlib">
<value>120</value>
</data>
<data name="querySyntaxDocsButton.TextImageRelation" type="System.Windows.Forms.TextImageRelation, System.Windows.Forms">
<value>ImageBeforeText</value>
</data>
<data name="$this.ClientSize" type="System.Drawing.Size, System.Drawing">
<value>981, 390</value>
</data>
<data name="mainTableLayoutPanel.ToolTip" xml:space="preserve">
<value />
</data>
<data name="querySyntaxDocsButton.ToolTip" xml:space="preserve">
<value />
</data>
<data name="zoomPercentageDropDown.Text" xml:space="preserve">
<value>Query Zoom: 100%</value>
</data>
<data name="&gt;&gt;queryEditorContextMenuStrip.Type" xml:space="preserve">
<value>System.Windows.Forms.ContextMenuStrip, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="querySyntaxDocsButton.Location" type="System.Drawing.Point, System.Drawing">
<value>852, 117</value>
</data>
<data name="executeQueryButton.TextImageRelation" type="System.Windows.Forms.TextImageRelation, System.Windows.Forms">
<value>ImageBeforeText</value>
</data>
<data name="&gt;&gt;executeQueryButton.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;executeQueryButton.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="queryEditorContextMenuStrip.ToolTip" xml:space="preserve">
<value />
</data>
<data name="&gt;&gt;closeButton.Type" xml:space="preserve">
<value>System.Windows.Forms.Button, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;closeButton.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="queryRichTextBox.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Bottom, Left, Right</value>
</data>
<data name="zoomPercentageDropDown.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wgAADsIBFShKgAAAAI1JREFUOE9j+Pbt239KMAOIcHJyIgujGPDh/UeSMMkGPL918v+JblMwTZYBJ7pN
/h+qlQIbQpYBEBeYEHbBpLOv/i+49BrDAHSM1YCsfS/+Sy98BMaEDMEwAFkzMYagGKDTsBJDMzZDQOzW
Ey8xDUDXhI5BGkEYxge5liQDsGGQqykyAISpZwAlmIFSAAAHNfyc4iTN4wAAAABJRU5ErkJggg==
</value>
</data>
<data name="showingCountLabel.Font" type="System.Drawing.Font, System.Drawing">
<value>Segoe UI, 9pt, style=Bold</value>
</data>
<data name="&gt;&gt;statusStrip.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="mainSplitContainer.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="toolStripStatusLabel1.Text" xml:space="preserve">
<value>Showing:</value>
</data>
<data name="statusStrip.Size" type="System.Drawing.Size, System.Drawing">
<value>981, 22</value>
</data>
<data name="showingCountLabel.Text" xml:space="preserve">
<value>0</value>
</data>
<data name="&gt;&gt;mainSplitContainer.Panel1.Type" xml:space="preserve">
<value>System.Windows.Forms.SplitterPanel, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;resultsGridView.ZOrder" xml:space="preserve">
<value>0</value>
</data>
<data name="&gt;&gt;mainSplitContainer.Type" xml:space="preserve">
<value>System.Windows.Forms.SplitContainer, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;percentage140.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="querySyntaxDocsButton.Size" type="System.Drawing.Size, System.Drawing">
<value>124, 26</value>
</data>
<data name="&gt;&gt;closeButton.Parent" xml:space="preserve">
<value>$this</value>
</data>
<data name="copyTextMenuItem.Text" xml:space="preserve">
<value>Copy</value>
</data>
<data name="mainTableLayoutPanel.Size" type="System.Drawing.Size, System.Drawing">
<value>979, 146</value>
</data>
<data name="pasteTextMenuItem.Text" xml:space="preserve">
<value>Paste</value>
</data>
<data name="&gt;&gt;resultsGridView.Name" xml:space="preserve">
<value>resultsGridView</value>
</data>
<data name="zoomPercentageDropDown.Size" type="System.Drawing.Size, System.Drawing">
<value>121, 20</value>
</data>
<data name="showingCountLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>14, 17</value>
</data>
<data name="mainTableLayoutPanel.Dock" type="System.Windows.Forms.DockStyle, System.Windows.Forms">
<value>Fill</value>
</data>
<data name="executeQueryButton.TabIndex" type="System.Int32, mscorlib">
<value>1</value>
</data>
<data name="mainSplitContainer.SplitterDistance" type="System.Int32, mscorlib">
<value>148</value>
</data>
<data name="queryExecutionStatusLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>55, 17</value>
</data>
<data name="&gt;&gt;toolStripStatusLabel1.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;mainSplitContainer.Name" xml:space="preserve">
<value>mainSplitContainer</value>
</data>
<data name="&gt;&gt;executeQueryButton.Name" xml:space="preserve">
<value>executeQueryButton</value>
</data>
<data name="&gt;&gt;toolStripStatusLabel2.Name" xml:space="preserve">
<value>toolStripStatusLabel2</value>
</data>
<data name="executeQueryButton.ImageAlign" type="System.Drawing.ContentAlignment, System.Drawing">
<value>MiddleRight</value>
</data>
<data name="queryRichTextBox.AutoScrollMinSize" type="System.Drawing.Size, System.Drawing">
<value>29, 16</value>
</data>
<data name="queryRichTextBox.ServiceColors" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAERGYXN0Q29sb3JlZFRleHRCb3gsIEN1bHR1cmU9bmV1dHJhbCwg
UHVibGljS2V5VG9rZW49ZmI4YWExMmI5OTRlZjYxYgwDAAAAUVN5c3RlbS5EcmF3aW5nLCBWZXJzaW9u
PTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUB
AAAAIkZhc3RDb2xvcmVkVGV4dEJveE5TLlNlcnZpY2VDb2xvcnMGAAAAKDxDb2xsYXBzZU1hcmtlckZv
cmVDb2xvcj5rX19CYWNraW5nRmllbGQoPENvbGxhcHNlTWFya2VyQmFja0NvbG9yPmtfX0JhY2tpbmdG
aWVsZCo8Q29sbGFwc2VNYXJrZXJCb3JkZXJDb2xvcj5rX19CYWNraW5nRmllbGQmPEV4cGFuZE1hcmtl
ckZvcmVDb2xvcj5rX19CYWNraW5nRmllbGQmPEV4cGFuZE1hcmtlckJhY2tDb2xvcj5rX19CYWNraW5n
RmllbGQoPEV4cGFuZE1hcmtlckJvcmRlckNvbG9yPmtfX0JhY2tpbmdGaWVsZAQEBAQEBBRTeXN0ZW0u
RHJhd2luZy5Db2xvcgMAAAAUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5c3RlbS5EcmF3aW5nLkNv
bG9yAwAAABRTeXN0ZW0uRHJhd2luZy5Db2xvcgMAAAAUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5
c3RlbS5EcmF3aW5nLkNvbG9yAwAAAAIAAAAF/P///xRTeXN0ZW0uRHJhd2luZy5Db2xvcgQAAAAEbmFt
ZQV2YWx1ZQprbm93bkNvbG9yBXN0YXRlAQAAAAkHBwMAAAAKAAAAAAAAAACWAAEAAfv////8////CgAA
AAAAAAAApAABAAH6/////P///woAAAAAAAAAAJYAAQAB+f////z///8KAAAAAAAAAACNAAEAAfj////8
////CgAAAAAAAAAApAABAAH3/////P///woAAAAAAAAAAJYAAQAL
</value>
</data>
<data name="&gt;&gt;$this.Name" xml:space="preserve">
<value>QueryEditor</value>
</data>
<data name="&gt;&gt;querySyntaxDocsButton.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="closeButton.Text" xml:space="preserve">
<value>Close</value>
</data>
<data name="percentage125.Size" type="System.Drawing.Size, System.Drawing">
<value>102, 22</value>
</data>
<data name="resultsGridView.ToolTip" xml:space="preserve">
<value />
</data>
<data name="timeElapsedLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>38, 17</value>
</data>
<data name="executeQueryButton.ToolTip" xml:space="preserve">
<value>(Shift + Enter)</value>
</data>
<data name="&gt;&gt;queryRichTextBox.Type" xml:space="preserve">
<value>FastColoredTextBoxNS.FastColoredTextBox, FastColoredTextBox, Culture=neutral, PublicKeyToken=fb8aa12b994ef61b</value>
</data>
<data name="percentage140.Text" xml:space="preserve">
<value>140%</value>
</data>
<data name="mainTableLayoutPanel.ColumnCount" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="&gt;&gt;showingCountLabel.Name" xml:space="preserve">
<value>showingCountLabel</value>
</data>
<data name="resultsGridView.RowHeadersWidth" type="System.Int32, mscorlib">
<value>24</value>
</data>
<data name="querySyntaxDocsButton.ImageAlign" type="System.Drawing.ContentAlignment, System.Drawing">
<value>MiddleRight</value>
</data>
<data name="closeButton.TabIndex" type="System.Int32, mscorlib">
<value>3</value>
</data>
<data name="copyTextMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wQAADsEBuJFr7QAAAw9JREFUWEftVs1PE0EU7x9AgvGmBsO+mW6d3e6WphjxiwIS/wRuHPSiR/4Cs+3y
UZVvotGTN24EjCa6uzTY8FksRCySKPHgQf8DuI6+tdM0UygtNOiBX/Ky2Xlv3vx25rfzXiBwhioQS+Ua
meXN6JaT1ZLu0mHGLGdDs9P35PknhmmnuyJT29wc3eSRyTyPTG5Llufm+CduDK9zc3SDh/vdh3KOE8Gw
F7pbnn/luuXsGkPp9ojtdZSaMeS06/3zffpghocfr/hkNHv+gZzn2IiOZa8bIznO7PQb2SfQmvSi4Sdr
nCXcfZ/ExOf6kjgK/m5M5rmWdObMQbfXnNjyj6ZmErFYrJEQMgMAWULIEhooSkZpuvAOLl/yxBildINS
el/Mi9jpu9GX3zmzXAffw8l0D+6IOb5VmyY0TesKhUJcVVWOz4MMfcFgUMT4yVufrTdpAx84s7yfLXb6
RiS5qLOEN22MfPTFWzUJQkgnJqaUbgeDwfZQKNRRajgGAH2EEIwRZPxtvjqYVVnC5dEXuxyPIJxa9kXp
P5+ucSPpGfJ6ZSgshMkXZJ8ApTSKOwAA+0gC4wWJ2HDuipZwN1nSyTHLWdYsN6NZzh6KWE+875RzlUEQ
UBRlUfYJlJCcU1W1VxyXICEDLyn/rkh5t2RfGURyFJrsExAxAODiu6qqPUVNAJSdNUs6K3UlIHRCCMmr
qnqTMaYTQqZlYQowy1utKwHGWHfpn1IQbdEK+igKru4E2traziuK8hbvAgBYI4SsUkqXASADAHtIAHdJ
xNedQCXgvII+ioudKgFK6co/JYDHcUbgvyCANUOM6Za7iJ3TKRJQebC5+Vp06sdF03a6tIS3g10Ss50i
qUNRDwJ4MamBgGJO7TyKvfrFzbG/vWTLgBuX48tQLwK0oUELT3zp0RLeN6yOmuXMxlJeoxxfhmqqYSUc
pIGaUFJqD+0HKgGJ43zG2G3ZVxVKKx3+SrUaIWSn0CUdbwcA4A5+QaWesJKJeZTSowV3EOLx+DlK6evS
SletYXyhW54FgKMFd4Y/+A3rSyMPm3Pf6gAAAABJRU5ErkJggg==
</value>
</data>
<data name="&gt;&gt;mainSplitContainer.ZOrder" xml:space="preserve">
<value>2</value>
</data>
<data name="percentage100.Text" xml:space="preserve">
<value>100%</value>
</data>
<data name="toolStripStatusLabel2.Text" xml:space="preserve">
<value>Results</value>
</data>
<data name="&gt;&gt;percentage100.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;percentage140.Name" xml:space="preserve">
<value>percentage140</value>
</data>
<data name="queryRichTextBox.Font" type="System.Drawing.Font, System.Drawing">
<value>Courier New, 11.25pt</value>
</data>
<data name="&gt;&gt;toolStripStatusLabel2.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;timeElapsedLabel.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripStatusLabel, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;mainTableLayoutPanel.Type" xml:space="preserve">
<value>System.Windows.Forms.TableLayoutPanel, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="&gt;&gt;mainTableLayoutPanel.Parent" xml:space="preserve">
<value>mainSplitContainer.Panel1</value>
</data>
<data name="mainSplitContainer.Panel2MinSize" type="System.Int32, mscorlib">
<value>150</value>
</data>
<data name="mainTableLayoutPanel.RowCount" type="System.Int32, mscorlib">
<value>2</value>
</data>
<data name="mainSplitContainer.Orientation" type="System.Windows.Forms.Orientation, System.Windows.Forms">
<value>Horizontal</value>
</data>
<data name="queryRichTextBox.TabIndex" type="System.Int32, mscorlib">
<value>0</value>
</data>
<data name="copyTextMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>102, 22</value>
</data>
<data name="closeButton.Size" type="System.Drawing.Size, System.Drawing">
<value>0, 0</value>
</data>
<data name="closeButton.ToolTip" xml:space="preserve">
<value />
</data>
<data name="&gt;&gt;mainSplitContainer.Panel2.ZOrder" xml:space="preserve">
<value>1</value>
</data>
<data name="querySyntaxDocsButton.Anchor" type="System.Windows.Forms.AnchorStyles, System.Windows.Forms">
<value>Top, Bottom, Left, Right</value>
</data>
<data name="pasteTextMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>102, 22</value>
</data>
<data name="&gt;&gt;percentage125.Name" xml:space="preserve">
<value>percentage125</value>
</data>
<data name="&gt;&gt;pasteTextMenuItem.Name" xml:space="preserve">
<value>pasteTextMenuItem</value>
</data>
<data name="&gt;&gt;queryRichTextBox.Name" xml:space="preserve">
<value>queryRichTextBox</value>
</data>
<data name="mainSplitContainer.Panel2.ToolTip" xml:space="preserve">
<value />
</data>
<data name="&gt;&gt;mainSplitContainer.Panel2.Name" xml:space="preserve">
<value>mainSplitContainer.Panel2</value>
</data>
<data name="&gt;&gt;percentage110.Type" xml:space="preserve">
<value>System.Windows.Forms.ToolStripMenuItem, System.Windows.Forms, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="toolStripStatusLabel1.Size" type="System.Drawing.Size, System.Drawing">
<value>56, 17</value>
</data>
<data name="&gt;&gt;resultsGridView.Type" xml:space="preserve">
<value>ParquetViewer.Controls.ParquetGridView, ParquetViewer, Culture=neutral, PublicKeyToken=null</value>
</data>
<metadata name="$this.Localizable" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="statusStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="executeQueryKeyboardShortcutToolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>126, 17</value>
</metadata>
<metadata name="queryEditorContextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>387, 17</value>
</metadata>
</root>

View file

@ -1,251 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="mainTableLayoutPanel.ToolTip" xml:space="preserve">
<value />
</data>
<data name="mainSplitContainer.Panel1.ToolTip" xml:space="preserve">
<value />
</data>
<data name="resultsGridView.ToolTip" xml:space="preserve">
<value />
</data>
<data name="mainSplitContainer.Panel2.ToolTip" xml:space="preserve">
<value />
</data>
<data name="mainSplitContainer.ToolTip" xml:space="preserve">
<value />
</data>
<assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<data name="queryEditorContextMenuStrip.Size" type="System.Drawing.Size, System.Drawing">
<value>117, 48</value>
</data>
<data name="queryEditorContextMenuStrip.ToolTip" xml:space="preserve">
<value />
</data>
<data name="queryRichTextBox.ServiceColors" mimetype="application/x-microsoft.net.object.binary.base64">
<value>
AAEAAAD/////AQAAAAAAAAAMAgAAAERGYXN0Q29sb3JlZFRleHRCb3gsIEN1bHR1cmU9bmV1dHJhbCwg
UHVibGljS2V5VG9rZW49ZmI4YWExMmI5OTRlZjYxYgwDAAAAUVN5c3RlbS5EcmF3aW5nLCBWZXJzaW9u
PTQuMC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49YjAzZjVmN2YxMWQ1MGEzYQUB
AAAAIkZhc3RDb2xvcmVkVGV4dEJveE5TLlNlcnZpY2VDb2xvcnMGAAAAKDxDb2xsYXBzZU1hcmtlckZv
cmVDb2xvcj5rX19CYWNraW5nRmllbGQoPENvbGxhcHNlTWFya2VyQmFja0NvbG9yPmtfX0JhY2tpbmdG
aWVsZCo8Q29sbGFwc2VNYXJrZXJCb3JkZXJDb2xvcj5rX19CYWNraW5nRmllbGQmPEV4cGFuZE1hcmtl
ckZvcmVDb2xvcj5rX19CYWNraW5nRmllbGQmPEV4cGFuZE1hcmtlckJhY2tDb2xvcj5rX19CYWNraW5n
RmllbGQoPEV4cGFuZE1hcmtlckJvcmRlckNvbG9yPmtfX0JhY2tpbmdGaWVsZAQEBAQEBBRTeXN0ZW0u
RHJhd2luZy5Db2xvcgMAAAAUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5c3RlbS5EcmF3aW5nLkNv
bG9yAwAAABRTeXN0ZW0uRHJhd2luZy5Db2xvcgMAAAAUU3lzdGVtLkRyYXdpbmcuQ29sb3IDAAAAFFN5
c3RlbS5EcmF3aW5nLkNvbG9yAwAAAAIAAAAF/P///xRTeXN0ZW0uRHJhd2luZy5Db2xvcgQAAAAEbmFt
ZQV2YWx1ZQprbm93bkNvbG9yBXN0YXRlAQAAAAkHBwMAAAAKAAAAAAAAAACWAAEAAfv////8////CgAA
AAAAAAAApAABAAH6/////P///woAAAAAAAAAAJYAAQAB+f////z///8KAAAAAAAAAACNAAEAAfj////8
////CgAAAAAAAAAApAABAAH3/////P///woAAAAAAAAAAJYAAQAL
</value>
</data>
<data name="queryRichTextBox.ToolTip" xml:space="preserve">
<value />
</data>
<data name="copyTextMenuItem.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAALGPC/xhBQAAAAlwSFlzAAAO
wQAADsEBuJFr7QAAAw9JREFUWEftVs1PE0EU7x9AgvGmBsO+mW6d3e6WphjxiwIS/wRuHPSiR/4Cs+3y
UZVvotGTN24EjCa6uzTY8FksRCySKPHgQf8DuI6+tdM0UygtNOiBX/Ky2Xlv3vx25rfzXiBwhioQS+Ua
meXN6JaT1ZLu0mHGLGdDs9P35PknhmmnuyJT29wc3eSRyTyPTG5Llufm+CduDK9zc3SDh/vdh3KOE8Gw
F7pbnn/luuXsGkPp9ojtdZSaMeS06/3zffpghocfr/hkNHv+gZzn2IiOZa8bIznO7PQb2SfQmvSi4Sdr
nCXcfZ/ExOf6kjgK/m5M5rmWdObMQbfXnNjyj6ZmErFYrJEQMgMAWULIEhooSkZpuvAOLl/yxBildINS
el/Mi9jpu9GX3zmzXAffw8l0D+6IOb5VmyY0TesKhUJcVVWOz4MMfcFgUMT4yVufrTdpAx84s7yfLXb6
RiS5qLOEN22MfPTFWzUJQkgnJqaUbgeDwfZQKNRRajgGAH2EEIwRZPxtvjqYVVnC5dEXuxyPIJxa9kXp
P5+ucSPpGfJ6ZSgshMkXZJ8ApTSKOwAA+0gC4wWJ2HDuipZwN1nSyTHLWdYsN6NZzh6KWE+875RzlUEQ
UBRlUfYJlJCcU1W1VxyXICEDLyn/rkh5t2RfGURyFJrsExAxAODiu6qqPUVNAJSdNUs6K3UlIHRCCMmr
qnqTMaYTQqZlYQowy1utKwHGWHfpn1IQbdEK+igKru4E2traziuK8hbvAgBYI4SsUkqXASADAHtIAHdJ
xNedQCXgvII+ioudKgFK6co/JYDHcUbgvyCANUOM6Za7iJ3TKRJQebC5+Vp06sdF03a6tIS3g10Ss50i
qUNRDwJ4MamBgGJO7TyKvfrFzbG/vWTLgBuX48tQLwK0oUELT3zp0RLeN6yOmuXMxlJeoxxfhmqqYSUc
pIGaUFJqD+0HKgGJ43zG2G3ZVxVKKx3+SrUaIWSn0CUdbwcA4A5+QaWesJKJeZTSowV3EOLx+DlK6evS
SletYXyhW54FgKMFd4Y/+A3rSyMPm3Pf6gAAAABJRU5ErkJggg==
</value>
</data>
<data name="copyTextMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>116, 22</value>
</data>
<data name="copyTextMenuItem.Text" xml:space="preserve">
<value>Kopyala</value>
</data>
<data name="pasteTextMenuItem.Size" type="System.Drawing.Size, System.Drawing">
<value>116, 22</value>
</data>
<data name="pasteTextMenuItem.Text" xml:space="preserve">
<value>Yapıştır</value>
</data>
<data name="executeQueryButton.Text" xml:space="preserve">
<value>İşle</value>
</data>
<data name="querySyntaxDocsButton.Text" xml:space="preserve">
<value>Sorgu Söz Dizimi</value>
</data>
<data name="querySyntaxDocsButton.ToolTip" xml:space="preserve">
<value />
</data>
<data name="statusStrip.ToolTip" xml:space="preserve">
<value />
</data>
<data name="toolStripStatusLabel1.Size" type="System.Drawing.Size, System.Drawing">
<value>63, 17</value>
</data>
<data name="toolStripStatusLabel1.Text" xml:space="preserve">
<value>Gösterilen:</value>
</data>
<data name="toolStripStatusLabel2.Size" type="System.Drawing.Size, System.Drawing">
<value>40, 17</value>
</data>
<data name="toolStripStatusLabel2.Text" xml:space="preserve">
<value>Sonuç</value>
</data>
<data name="toolStripStatusLabel4.Size" type="System.Drawing.Size, System.Drawing">
<value>637, 17</value>
</data>
<data name="zoomPercentageDropDown.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>
iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8
YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAACNSURBVDhPY/j27dt/SjADiHByciILoxjw4f1HkjDJBjy/
dfL/iW5TME2WASe6Tf4fqpUCG0KWARAXmBB2waSzr/4vuPQawwB0jNWArH0v/ksvfATGhAzBMABZMzGG
oBig07ASQzM2Q0Ds1hMvMQ1A14SOQRpBGMYHuZYkA7BhkKspMgCEqWcAJZiBUgAABzX8nOIkzeMAAAAA
SUVORK5CYII=
</value>
</data>
<data name="zoomPercentageDropDown.Size" type="System.Drawing.Size, System.Drawing">
<value>120, 20</value>
</data>
<data name="zoomPercentageDropDown.Text" xml:space="preserve">
<value>Sorgu Zumu: 100%</value>
</data>
<data name="queryExecutionStatusLabel.Size" type="System.Drawing.Size, System.Drawing">
<value>54, 17</value>
</data>
<data name="queryExecutionStatusLabel.Text" xml:space="preserve">
<value>İşleniyor:</value>
</data>
<data name="closeButton.ToolTip" xml:space="preserve">
<value />
</data>
<data name="$this.Text" xml:space="preserve">
<value>ParquetViewer - Sorgu Editörü (DuckDB Desteğiyle)</value>
</data>
<data name="$this.ToolTip" xml:space="preserve">
<value />
</data>
</root>

View file

@ -360,6 +360,15 @@ namespace ParquetViewer.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Frozen.
/// </summary>
internal static string FrozenColumnText {
get {
return ResourceManager.GetString("FrozenColumnText", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Image saved to {0}.
/// </summary>

View file

@ -394,4 +394,8 @@ You can always toggle this on/off from the Edit menu.</value>
<value>Byte arrays not supported</value>
<comment>Shown when a byte[] type is in the results in the Query Editor window. As these types are currently not supported by DuckDB.</comment>
</data>
<data name="FrozenColumnText" xml:space="preserve">
<value>Frozen</value>
<comment>When the user right-clicks on a column header this is the text shown for freezing the column. Freezing a column makes it so it is always visible no matter how much you scroll horizontally.</comment>
</data>
</root>

View file

@ -333,4 +333,7 @@ Tercihinizi Düzen menüsünden istediğiniz zaman değiştirebilirsiniz.</value
<data name="ByteArraysNotSupportedErrorTitle" xml:space="preserve">
<value>Byte[] tipli sonuçlar desteklenmemektedir</value>
</data>
<data name="FrozenColumnText" xml:space="preserve">
<value>Dondur</value>
</data>
</root>