WL#8134: Make metadata information transfer optional

Affects: Server-8.0   —   Status: Complete   —   Priority: Medium

Using COM_QUERY command, the client sends to the server an SQL statement to 
execute.
In response the client can get 4 different answers from the server:
a) ERR_PACKET (0xFF) - in case of an error;
b) OK_PACKET (0x00) - when no resultset;
c) LOCAL_INFILE_PACKET (0xFB) - for "LOCAL INFILE..." queries;
d) RESULTSET - for queries that return results.

RESULTSET contains a bunch of packets:
- metadata;
- EOF_PACKET if not CLIENT_DEPRECATE_EOF flag set;
- data rows;
- OK_PACKET (or EOF_PACKET if not CLIENT_DEPRECATE_EOF flag set) or
  ERR_PACKET

RESULTSET's metadata consists of:
- column count (n);
- n * column definitions

Each column definition consists of:
- catalog
- schema
- table alias
- table
- column alias
- column name
etc.

Constructing/parsing and sending/receiving resultset metadata consume server, 
client and network loads.
In some cases metadata size can be much bigger than actual result data size
and the metadata is just not needed.
We can significantly speed up the query result transfer by completely disabling
the generation and storage of these data.
This worklog is to add a possibility to turn resultset metadata generation and 
transfer optional.
FR1. Add CLIENT_OPTIONAL_RESULTSET_METADATA flag.
FR2. Add/handle server resultset_metadata session variable.
FR3. Handle resultsets with optional metadata the client library.

NFR1. Ensure mysql_fetch_field(), mysql_fetch_field_direct(), mysql_fetch_fields() 
functions don't fail.
NFR2. Ensure that there will be NO protocol changes for clients that don't set 
CLIENT_OPTIONAL_RESULTSET_METADATA and they will operate properly.
New clients must inform the server that they can handle optional metadata.
In order to do that the client set CLIENT_OPTIONAL_RESULTSET_METADATA (better 
name?) flag.

New enum session variable resultset_metadata (better name?) controls what 
metadata will be sent to the client.
Possible @@resultset_metadata values are:
- NONE, no metadata will be sent.
- FULL (default), to send all metadata;

We can add more options in the future e.g. to send only column's aliases or 
whatever.

The server sends the following in response to COM_QUERY command:
- column count;
- 1-byte metadata flag (0 - NONE, 1 - FULL)
- metadata if the flag is not 0,
- data rows;
- OK_PACKET (or EOF_PACKET if not CLIENT_DEPRECATE_EOF flag set) or
  ERR_PACKET

COM_STMT_PREPARE response will be changed the same way:
send 1-byte metadata flag (0 - NONE, 1 - FULL),
then send metadata if the flag is not 0,
======================================================

According to : https://www.facebook.com/weixiang.zhai/posts/678596755543802

After porting twitter’s patch ( Great thanks to Davi Arnaut) to MySQL5.6.16, I
slightly changed it to make protocol_mode support more options:

0/METADATA_FULL: return all metadata, default value.
1/METADATA_REAL_COLUMN: only column name;
2/METADATA_FAKE_COLUMN: fake column name ,use 1,2...N instead of real column 
name
3/METADATA_NULL_COLUMN: use NULL to express the metadata information
4/METADATA_IGNORE: ignore metadata information, just for test..

CREATE TABLE `test_meta_impact` (
`abcdefg1` int(11) NOT NULL AUTO_INCREMENT,
`abcdefg2` int(11) DEFAULT NULL,
`abcdefg3` int(11) DEFAULT NULL,
`abcdefg4` int(11) DEFAULT NULL,
……
……
`abcdefg40` int(11) DEFAULT NULL,
PRIMARY KEY (`abcdefg1`)
) ENGINE=InnoDB AUTO_INCREMENT=229361 DEFAULT CHARSET=utf8

mysqlslap --no-defaults -uxx --create-schema=test -h$host -P $port
--number-of-queries=1000000000 --concurrency=100 --query='SELECT * FROM
test.test_meta_impact where abcdefg1 = 2'

METADATA_FULL : 3.48w TPS, Net send 113M
METADATA_REAL_COLUMN: 7.2W TPS, Net send 111M
METADATA_FAKE_COLUMN: 9.2W TPS , Net send 116M
METADATA_NULL_COLUMN: 9.6w TPS , Net send 115M
METADATA_IGNORE: 13.8w TPS, Net send 30M
include/mysql_com.h
===================
/**
  The client can handle optional metadata information in the resultset.
*/
#define CLIENT_OPTIONAL_RESULTSET_METADATA (1UL << 25)


sql/system_variables.h
======================
/** Values for resultset_metadata sysvar. */
enum enum_resultset_metadata {
  /** The server will send all metadata. */
  RESULTSET_METADATA_FULL= 0,
  /** No metadata will be sent. */
  RESULTSET_METADATA_NONE
};


sql/sys_vars.cc
===============
static const char *resultset_metadata_names[]= {"FULL", "NONE", NullS};
static Sys_var_enum Sys_resultset_metadata(
       "resultset_metadata",
       "Controls what meatadata the server will send to the client: "
       "either FULL (default) for all metadata, NONE for no metadata.",
       SESSION_ONLY(resultset_metadata),
       NO_CMD_LINE,
       resultset_metadata_names,
       DEFAULT(RESULTSET_METADATA_FULL));