Goal: Pass all 4259065 tests in sqllogictest in 1 week
github.com
github.com
e.g. What table and value representation was used?
FWIW I suspect using a LALR(1) parser in Zig on the sqlite grammar would have saved some time and gotten past the parsing headache.
The sqllogictest comes directly from sqlite, so it seems like the parsing problem is mostly "port from C to Zig" (which are very similar metalanguages, or I guess meta- meta- languages in this case :) )
Lemon is apparently a mini-yacc, just for sqlite's grammar, and is about 7K lines of C code, with no deps: https://sqlite.org/src/doc/trunk/doc/lemon.html
Optimizer/query planner worked by parsing the query as a tree of operations and then finding tree transformations which are equivalent. Most basically this involved swapping table join orders and trading between materializing and streaming operators(^0). Costing was based on histograms data histograms which essentially enabled estimating how many rows each node in the query tree is expected to return. Generally you want to reduce the number of rows you are materializing ASAP. This generally means joining tables with fewest rows first, because then you can efficiently scan larger tables. Default strategy for joining large tables was to scan smaller one and build a map of the values and then scan the other one checking the map for each record. An alternative strategy is to build a bloom filter instead of the map, but that is only more efficient if the cross-section of the join is small.
Virtual execute evaluate interface enabled a lot of custom execution strategies for selecting from row/column/external db based tables, sorting data, and tons of join strategies.
Note 0: The constraint with streaming operators is that you can't fully sort the data before next step is executed. This prohibits execution strategies such as efficient joins which require all data to be sorted.
If you want to know how sqlite does that, it has good docs about it, particularly https://sqlite.org/opcode.html
Though I do think it's illumating to see the smallest, slowest code that implements the spec
Similar to the "500 lines or less" book, or say a TCP/IP implementation in Python
I cloned it, and it's ~3600 lines, which is very interesting. I didn't think you could implement anything that passes 95% of an sqlite test suite in that much code, as sqlite itself is at least 200K lines IIRC.
It has a ton of features built up over 20 years. Sure you save a lot by not having a disk pager, efficient data structures, and so forth, but still that's pretty small, and parsing/tokenizing is over 1000 lines of it.
The generated tests are not designed to test a wide breadth of features of the SQL language, and passing them with a simple engine is very doable. A lot of the value of these tests is that the sheer volume of queries tends to find obscure problems in optimizers that would not easily surface otherwise. That is of course not a problem in a simple engine that does not have an optimizer.
[1] https://www.sqlite.org/testing.html#test_harnesses
[2] https://github.com/gregrahn/sqllogictest/blob/master/test/ra...
[3] https://raw.githubusercontent.com/gregrahn/sqllogictest/mast...
The numbers could be misleading because the 5% of failing tests could be a large part or most of the core language (window functions?), while the 95% are some combinatorial tests that happen to take the exact same code path in an unoptimized engine
i.e. with 4.2 million tests for 2600 lines, it seems like you're going to have a lot of duplicate coverage, even accounting for state space explosion
- on the input side, write a Tokenizer in Zig and feed that into the generated state machine in C
- on the output side, consume Lemon's C data structures / function calls directly in Zig. This is probably the hard part as the grammar and semantic actions are very intertwined
That would be a cool demo, although honestly maybe not even less work
At the veeeery bottom:
> Detailed writeup to follow probably in a week or two.
I bet the zig project would be interested in the sha of the tree that blows up their compiler
If you look at the issue in question you'll see that it's not a bug, but a proposal to change the semantics of the language; rules about when something is comptime-known or not. If you replace `@compileError` (comptime effect) with `std.debug.print` (runtime effect) the print statement is never reached.
Your claim is false.
Do you have an example? Sounds like a catastrophic edge case.
* 10349: already fixed in master branch; issue remains open until we add behavior test coverage for it.
* 9810: same
* 8952: same
* 4491: same
* 3882: same
* 5230: same
* 6444: duplicate of 5230
* 7097: duplicate of 5230
I went through 100% of your links and 100% of them are solved already. The only reason they are open is because we are being responsible and not closing them until we have verified that each and every case has behavior test coverage.
If zig was being developed using a process where correctness mattered one jot, then the underlying issue wouldn't have kept happening and you wouldn't have kept papering over a fundamentally wrong model. While I did not compare zig to V, now that you brought it up in a related comment, you're right, they do seem to follow very similar development models: "That's not an issue, and even if it is an issue, we've already fixed it, and even if we haven't fixed it, it doesn't matter, and even if it matters, it's not our job, and even if it is, you can't prove it." Wow.
Zig is a toy language with a broken implementation. The comptime story is incoherent; it is two entirely unalike languages being written with superficially similar (but not identical) syntax, and lots of bugs in the gaps. At least V is honest about what it is and isn't.
ETA: I provided links, do you have any evidence whatsoever that any of these issues have been fixed? Because I went through these links and 0% of them have commits attached. 0% of them have comments from a developer indicating they've been fixed (other than comments posted after I shared links). 0% of them have comments from a developer saying that they're being held open in order for testcases to be added. Your claims are just more confabulation from a confirmed liar.
All software with any amount of complexity has bugs, even if there’s a published spec ratified by comittee over the course of 20 years, or whatever your unattainable standard of quality is.
Zig is free software and a community in the best sense of both.
Show some respect.
And I do obviously know who I was interacting with; Kelley's arrogance and lies are legendary (second only to the V devs, but he appears to be consciously competing with them). It drove me away from the language when my own filed bug on this issue was met with a similar response.
> Zig has known bugs and even some miscompilations.
> Zig is immature. Even with Zig 0.9.0, working on a non-trivial project using Zig will likely require participating in the development process.
I don't know why you have it out for me. But as long as your HN account isn't blocked by mods for trolling I'm stuck endlessly refuting your claims.
If you have a language or project as complex as Zig and can provide Andrew with some sort of guidance on better implementation / OSS issue management, I would love to see this. Otherwise, I would encourage you to not post comments criticizing work which you're not qualified to criticize.
@jamii seems super talented, but his bio says "in the past I've built database engines, query planners, compilers, developer tools and interfaces for [a...] myriad [of] consulting and personal research projects.", along with his repo's being related to SQL parers, or literal text-editors working purely on string manipulation. He is also sponsored to spent 100% of his time doing exactly this.
What I mean that he is almost definitely a 10x dev at writing SQL parsers. But ask him to write a shader that renders a neat waterbed material and he'd be likely a 0.8x dev? The overlap between experience and context is key.
That said, I can't think of any technical domain where I could do this, even if provided with all the tests up front.
My experience with the phrase is people mean finding a "diamond in the rough" who can code circles around anyone else. It's not about finding a Norvig or Carmack, it's about finding a fresh graduate that you can stick on a problem and they will be bountifully productive.
It's basically a manager's wet dream: extremely productive but cheap. In my experience real 10x people appear to be the opposite: seemingly slow but incredibly expensive. Everyone I actually consider 10x makes millions. And of those that are friends, they didn't really reach that 10x stage until their 30s or 40s.
It's something you get from other people. There's not a good test to figure out if you're 10x better than some randomly picked average developer.
What fraction of devs could even complete this, let alone in merely 10x the time?
I think the actual pushback of the 10x programmer idea is that it's more often used to bully regular programmers into working longer hours, rather than actually identifying top performing programmers.
Like 25%? But that’s really only because of the influx of people doing it for money.
If you’d asked me the same thing 15 years ago I’d have said 80%.
If you also don't follow specific developers online then you might not notice any. Here are a few I've seen for which 10x is probably an underestimate!
* David Tonlay and Alex Crighton - feels like they've written half the Rust ecosystem between them. * Eric Traut (Pyright author) - seriously go and check out Pyright's bug tracker. It's insane.
I think it would be more reasonable to call someone a 3 -sigma dev (someone 3 standard deviations above the mean. These would exist because that's how stats work)
The gambit is that a mediocre programmer would take 10x as long to write the same code as the hypothetical 10x dev. But that’s not what a mediocre or even average dev does: they solve the problem in an entirely different (and, for purposes of this argument, less optimal) manner in some spam of time that may or may not be longer than a qualified hacker or a theoretical 10x dev. Almost all CS problems have multiple solutions, so you’re not likely to find one where there is only one solution and it takes one guy x and the other guy 10x as long.
Also, you're not guaranteed to have an example 3 standard deviations above the mean. It strongly depends on your distribution and sample size.
You're right about the sufficient sample size.
To me, the more likely explanation is that this guy is an excellent developer, working on a problem he was suited to, and that's about all you can say. He came up with good strategies and insights here, and worked hard, and did a lot of other stuff right. But the idea of a generically 10x developer is a cartoonish oversimplification of how the world works.
I also propose that moniker be banned from being self-applied, and is in fact, a smell test: if you encounter a colleague calling themselves a 10x developer, start interviewing immediately. No good will come out of that.
The majority of the team couldn't understand his code. We'd have newly hired senior developers just leave rather than deal with it.
He'd rolled his own code generator for our data model that did everything from model generation to the web controllers.
The result was that while he could pump out work quickly, what would've otherwise been a quick fix for a graduate developer now required a deep understanding of a complex system.
This had the effect of turning what would have otherwise been a team of 1-2x developers into a team of 0.2-0.5x devs with a retention problem.
Anytime he "improved" a module, no one else could maintain it as that would entail additional rule-breaking, which was verboten for mortals, so only he could maintain code he touched. Combined with the fact that he didn't add any tests: the net result was he was slowly and surely subverting the codebase into his personal, brittle domain that no one else could change. He was slowing everyone else done, but all management was looking at was his velocity at closing bugs or rolling out new features while creating tech-debt. His boastful personality was just the icing on the cake.
There was a great deal of thought put into it and he could extend and modify the output really quickly.
The complexity of the system basically made it so that what would otherwise have been a simple task achievable by a graduate required a deep understanding to carry out.
Heh, I've actually done that... twice. Luckily it was a team of 1 and I wouldn't expect anyone else to understand my mess. The code generation was extra ugly since I planned to get rid of it eventually to craft out smaller details. It was great at doing repetitive work in bulk. Not sure if it was actually faster but at least it was less boring doing things that way.
The difference, of course, the framework has extensive documentation.
So that was the missing ingredient.
He made a framework, but wrote no documentation. Writing documentation would have made everyone an n*x developer, for some value of n > 1.
Also, it's good if language doesn't stand in your way.
Surely at that point it would've been a lot cleaner and more practical to just edit the one file you need to parse, to remove the weird line breaks, etc., rather than building special cases into your parser to work around those lines? What am I missing?
Not always the best way, but usuaully the easiest thing that works for me.
https://GitHub.com/samsquire/hash-db
It's distributed dynamodb style keyvalue, SQL and Cypher graph database.
I feel if you want to get a project moving forward for something as large as a database, you can get something rudimentary working and extend the parser when you need those features.
SQL wise it supports Joins and where's and rudimentary full text search It uses rockset's converged indexes for ease of query generation.
If you're interested in queries then you should read this blog post. https://rockset.com/blog/converged-indexing-the-secret-sauce...
The database is partly multimodel with document storage and SQL and graph Cypher querying but I am yet to get all the models to be mutually queryable. The document storage is queryable by SQL but graphs aren't queryable by SQL or as a document.
You either get a curl sh, a tarball, or a wrapper around either of those that pretends to be a .deb or .rpm.
One hopes.
This way you are providing a one-stop shop that can easily be run. I have all kinds of tools that are docker containers because its simpler to not have to worry about all kinds of library mismatches or locations of shared libraries, and instead ship a minimal docker container instead.
https://hub.docker.com/r/stedolan/jq
Yes, it's despicable.
Binaries are provided on the Releases page, so all you need to do is download one, put it in /usr/local/bin, and it’s essentially guaranteed to work.
To upgrade, you download the new release and overwrite it.
There’s an argument to be made for not having the version information available for dependency resolution (for scc as a dependency) available in your package manager, but you have to admit that it’s easy enough to install. GitHub doesn’t even mind if you `wget && chmod` from their CDN URL.
"Processing 40 TB of code from ~10M projects with a server and Go for $100 (2019)"
He didn't invent SQL. He had to take the grammar from somewhere.
You wanted him to handwrite it copied from the ANSI SQL paper?
Or to just think up all the possible grammars and ignore the real paper?
How would that be different or better than this?
Personally I do agree that, when writing a language interpreter and claiming "no dependency", grabbing an existing parser is a bit of a cheat. Just like grabbing an existing bytecode VM, garbage collector, just-in-time engine, ... would be. It doesn't make the endeavor less interesting or less formidable, but it doesn't really fit "no dependencies" any more.
Huh? He wrote the parser generator. https://github.com/jamii/hytradboi-jam-2022/tree/main/lib/sq...
> I only have to parse sqlite grammar, and even then probably only a fraction of it. So it looks like writing a parser generator might be plausible and by now it's really my only option if I want to get any tests passing at all.
> So here's my grammar so far. It's parsed by GrammarParser. In theory I could do this at comptime, but until we get a comptime allocator that's going to be a yak shave and I am way too many yak shaves deep already. So I laboriously but reliably write out all the rules into grammar.zig.
> The Tokenizer is written by hand and seems to be basically done - it runs without complaint on the entire test set. I might discover bugs there later, of course.
> The Parser is fun. There is a single parse function, but because it reads the rules from grammar.zig at compile time it gets specialized for each parse rule. Basically I got the same result as hand-generating the parser code, without having to splices a bunch of strings together. After the jam maybe I'll have some yak shave time to cut out grammar.zig entirely and do all the grammar stuff at comptime, and then it'll be a pretty sweet system.
> The best part about this is that I get really nice parse trees by generating rich types from the input grammar. Eg.
And also:
> I made some changes to the parser generator, added a whole bunch of debugging tools to the parser itself and then sat down and cranked on the grammar till I can parse 100% of the tests. I'm finally out of the damn tunnel.
Copying the BFN "from an external source" is a smart move, since it means they don't have to do lots of busy work slowly reading and transcribing the specification; someone's already done that step, so why would anyone expect the author to waste time?
Using a parser generator is also a smart move since they exist already and are used all over the place (nobody hand-writes parsers for large languages; that's just a needless source of tedium and bugs). The code that's spit out of the parser generator is novel; that's newly created code which isn't taken from someone else's Github/other repo.
Ultimately, I don't see how any of what the author's done constitutes "[relying] on a dependency" given that they're not using anyone elses Zig source code in their compiled binary, they're writing lots of code for themselves to use, just very quickly, and with powerful tools.
That is absolutely not true! In fact, most major programming language implementations use handwritten parsers [0].
That said:
> Using a parser generator is also a smart move since they exist already
Jamie wrote the parser generator here too. So it's all the more "from scratch".
[0] https://notes.eatonphil.com/parser-generators-vs-handwritten...