
Is it possible to fit the source MySQL client on
1 page of A4 format ? It turns out that if 8 pt (in principle readable) and after obfuscation, then you can! And if a normal code without obfuscation and 10 size, then it is impossible: you need
as many as 6 pages .
In the course of working on everyone, I accidentally turned out to be a tiny, but working MySQL client of a little more than 1000 lines. It became interesting how much more compact you can do. Spent half Sunday, isolated and minimized code. As a result,
nanomysql , CLI client for MySQL appeared , the
full source of which takes
slightly less than 380 lines and about 10500 bytes , and at the same time compiles and runs under Linux, Windows, MacOS. Written in C ++ with absolute minimum STL.
Screenshots, tsiferki and other details weekend-madness on the manufacture of nanoclients under the cut.
To begin with, the promised mega-screenshot!
')
Z:\work\nanomysql>nanomysql.exe -u testme -p moo connected to mysql 5.5.25a-log nanomysql> use test --- ok, 0 row(s) nanomysql> select * from t id, gid, body --- 2, 1, three abcx four 3, 1, five six seven abcx 4, 1, eight in abcx-nine 5, 1, one two three in abcm 6, 1, binlog ftw 100, 1, one two abcx --- ok, 6 row(s) nanomysql> quit bye
Update: plus tableshot obfuscated sources !!! The picture is clickable.

The client can handle (send or receive and parse) 7 types of network packets: handshake, auth, query, ok, error, field, row. To cling to the server, send requests and show results, more in general, and not necessary. So, the initial version, separated into 1 file and compiled with fan cut-n-paste from different places of the source code (see “robbing on areas, just to get together”) was immediately small and occupied ~ 1250 lines. Therefore, the purpose of entertainment was set at 500 lines.
This version was able to log in to the server with a hard-coded login and password and make one hard flashed test request. Stupidly throwing out unnecessary code altogether (basically all sorts of completely unused methods were thrown right out entirely), well, having added a small console query loop at the same time, we managed to quickly bring it to ~ 700 lines.
At this point, I had to climb inside the classes and methods. Three sources of space saving happened here:
- merging classes together (and initially instead of the MysqlDriver_t class there were three of them, NetInputBuffer_c + NetOutputBuffer_c + MysqlDriver_t itself),
- skipping methods inside the class declaration (saving on a copy of the signature and empty strings),
- simplification of the generalized code inside the methods for our particular case.
Well, of course, there is always a dot sweep of individual lines. These simple measures reached approximately ~ 500 lines.
At the same time, during the descent to the level of 500, I added an analysis of the command line options and made the conclusion a little more beautiful. The changes were mixed with others, due to the elimination of the code, and in general, commits, adding functionality, reduced the number of lines. It is always very pleasant to do more functionality and at the same time to erase the code! Even in the course of this part, it became clear that in the pursuit of lines, the usual standard code would have to be slightly violated: throw out assert () completely, format the code “in a column” instead of a Christmas tree, and in some places vice versa, in a line instead of a column "And generally write somewhat at odds with each other. The key criterion was to preserve the readability of those places, which in principle should be read. (Some magical transformations in the implementation of SHA1, for example, make no sense to read, and moreover, they did not immediately appear.)
And then suddenly another interesting question arose: is it possible to shove a customer at all on 1 page! And a readable font, not a QR code, of course. On the one hand, of course, 500 lines. But these are rather short lines, and with comments and empty lines. Plus, the total text of only ~ 12 kilobytes, is already comparable in order.

In other words, let's obfuscate and set aside the code brick !!!
Literally brick, in order to save precious symbols. You can see the result here,
nanosql1.pdf (disclaimer: just some strange first file hosting in Google, because habrastorage does not accept PDF).
I fiddled a little by hand, it became clear that I needed a script. Wrote a script obfuscator. (After it, the code must be additionally slightly corrected by hand, but correcting it in 3-4 places is quite simple and the script is already too lazy to correct.)
The elimination of comments and empty lines gives from ~ 10.5k approximately ~ 7.3k, the length of a line with a size 9 with narrow fields turns out 105 characters per line, size 8 respectively 118 characters, about 60 lines on a page. That is, simply removing the empty places is not good enough, plus you can see that all sorts of long identifiers in the code are eating a lot of space. I added several more lines to the script so that the original variable names of the type m_iSock, m_pReadBuf should be changed to one and two-letter p, q, a0 and so on. The result is much better, about 5.5k.
Then C ++ allows you to make the C ++ language from the preloaded code just fine! After replacing identifiers, the border often falls somewhere, where you can simply take and insert a line break. And where it is impossible (for example, in the middle of the word printf) you can always put \ and move the string.
At the same time, the preprocessor directives are eating most of the paper and nothing special can be done with them, just minimize the number of #include and other #ifdefs. It is possible to save precious lines a bit more by private tricks: for example, substituting the numbers for the defined constants with the #define MAX_PACKET 16777216 directly into the code, and in the form (1 << 24) for compactness. In the end, the transformed code can almost be sent to
IOCCC , only you need to format it instead of a brick in ASCII image of a dolphin from the MySQL logo.
I also tried the tricks #define R return, #define V void and so on. The necessary sense from them did not work. It is precisely to reduce the number of lines they do not give, the program is too short. Well, we replaced 6 bytes of return with 1 byte of R and 20 times, saved 100 bytes or minus 1 long string. And plus 1 added # define, in the end there is no sense.
Obfuscation and final cuts of both obfuscated and readable versions of the code were interleaved here and there. The tricks are the same; of the interesting, except that the alteration of the functions SHA1_Init () and so on for the class (just save the lines and tokens) and then chaining the sha.Init (). Update (). Final () calls in 1 line instead of the 3 line column.
The result was the version with 377 lines and Sunday evening, you had to stop. ;) Probably, you can finish it even stronger, achieve 300 lines, or there are bricks on 1 page with a ninth, not eighth, size, but this is not very interesting.
Total
A completely working MySQL client managed to write in 380 lines. It is clear that it is practically useless, anyway everywhere there is a much smarter native client. But as an example, “what can be written in the evening and 400 lines” is very indicative, I think.
Obfuscated version of the client manages to drive in ~ 5 kilobytes and fit on 1 page of A4. This, of course, pure entertainment. But on the strange question "Is it possible for the MySQL client to fit on A4" a convincing affirmative answer was received.
Statistics on the 377 lines is as follows:
- 34 lines #include, #define, void die ();
- 150 lines MysqlDriver_t: basic network buffer, parsing part of packets (ok, error, field, row);
- 74 lines SHA1_t: authentication SHA-1 for authentication (auth package);
- 81 line, start of main (): parsing options, network connection, authentication;
- 30 lines, end of main (): query loop, read the query, send, receive, print the answer.
Who has not converged balance, remember about empty lines and comments.
What is the moral of this fable? And there is no morality, Nautilus is right. But some organizational conclusions can be done. For example, that everywhere and always there is swelling and swelling of the code, do not hesitate to ruthlessly throw out garbage. For example, that IOCCC is available to everyone. ;) Or, for example, that a completely working prototype of a complex, seemingly at first glance, code can be made surprisingly quickly and surprisingly compact.
The last, in my personal opinion, the main thing. Write prototypes, it's fast and cool.