Category: MySQLDevelopment

MySQL Internals Coding Guidelines

← Back to MySQL Internals overview page

Contents

[edit] Coding Guidelines

This section shows the guidelines that MySQL's developers follow when writing new code. Consistent style is important for us, because everyone must know what to expect. For example, after we become accustomed to seeing that everything inside an if is indented two spaces, we can glance at a listing and understand what's nested within what. Writing non-conforming code can be bad. For example, if we want to find where assignments are made to variable mutex_count, we might search for mutex_count with an editor and miss assignments that look like mutex_count = with a space before the equal sign (which is non-conforming). Knowing our rules, you'll find it easier to read our code, and when you decide to contribute (which we hope you'll consider!) we'll find it easier to read and review your code.

[edit] General Development Guidelines

shell> bzr branch lp:mysql-server mysql-trunk

[edit] C/C++ Coding Guidelines of MySQL Server

This section covers guidelines for C/C++ code for the MySQL server. The guidelines do not necessarily apply for other projects such as MySQL Connector/J or Connector/ODBC.

[edit] How we maintain the server coding guidelines

We are committed to have a single coding style for core MySQL server. Storage engines, however, may have an own coding style: Falcon and NDB styles are documented later in this manual.

The server coding style is governed by a group of representatives from each technical team: Optimiser, Runtime, Replication, Backup Engines and the "general" team.

Currently these representatives are:


The group accepts and considers change proposals. Each proposal must include an implementation strategy, and is first published on Internals mailing list for a public discussion. When the discussion is over, the group of representatives holds a vote, and the change is accepted if it's approved by a simple majority of the ballots. The submitter of the change request then carries out its implementation.

Now to the coding style itself.

[edit] Indentation and Spacing

Correct:

if (a)

Incorrect:

if (a)<SP><SP><TAB><SP>

Remove trailing spaces if you are already changing a line, otherwise leave existing code intact.

{
  code, code, code
  {
    code, code, code
  }
}
namespace foo
{
class Bar
{
  Bar();
};
}  // namespace foo
int function_1()
{
  int i;
  int j;

  function0();
}


int function2()
{
  return;
}

if (code, code, code)
{
  code, code, code;
}
for (code, code, code)
{}
switch (condition)
{
case XXX:
  statements;
case YYY:
  {
    statements;
  }
}
Type      value;
int       var2;
ulonglong var3;
a/= b;
return_value= my_function(arg1);
...
int x=          27;
int new_var=    18;

Align assignments from one structure to another, like this:

foo->member=      bar->member;
foo->name=        bar->name;
foo->name_length= bar->name_length;
int x= 11; int y= 12;

z= x; y+= x;

This is right:

int x= 11;
int y= 12;

z= x;
y+= x;
int *var;

if ((x == y + 2) && !param->is_signed)
  function_call();
ln= mysql_bin_log.generate_name(opt_bin_logname, "-bin", 1, buf);
if (sig != MYSQL_KILL_SIGNAL && sig != 0)
  unireg_abort(1);
else
  unireg_end();
while (*val && my_isspace(mysqld_charset, *val))
  *val++;
Return_value_type *Class_name::method_name(const char *arg1,
                                           size_t arg2, Type *arg3)
return_value= function_name(argument1, argument2, long_argument3,
                            argument4,
                            function_name2(long_argument5,
                                           long_argument6));
return_value=
  long_long_function_name(long_long_argument1, long_long_argument2,
                          long_long_long_argument3,
                          long_long_argument4,
                          long_function_name2(long_long_argument5,
                                              long_long_argument6));
Long_long_return_value_type *
Long_long_class_name::
long_long_method_name(const char *long_long_arg1, size_t long_long_arg2,
                      Long_long_type *arg3)

(You may but don't have to split Class_name::method_name into two lines.) When arguments do not fit on one line, consider renaming them.

Item::Item(int a_arg, int b_arg, int c_arg)
  :a(a_arg), b(b_arg), c(c_arg)
{}

But keep lines short to make them more readable:

Item::Item(int longer_arg, int more_longer_arg)
  :longer(longer_arg),
  more_longer(more_longer_arg)
{}

If a constructor can fit into one line:

Item::Item(int a_arg) :a(a_arg) {}

[edit] Naming Conventions

class Item;
class Query_arena;
class Log_event;
#define MY_CONSTANT 15
 

[edit] Commenting Code

/*
  This is how a multi-line comment in the middle of code
  should look.  Note it not Doxygen-style if it's not at the 
  beginning of a code enclosure (function or class).
*/

 /* ********* This comment is bad. It's indented incorrectly, it has
 *            additional asterisks. Don't write this way.
 *  *********/
 /* We must check if stack_size = Solaris 2.9 can return 0 here. */
 // We must check if stack_size = Solaris 2.9 can return 0 here.
{
  qc*= 2;                                     /* double the estimation */
}
struct st_mysql_stmt
{
...
  MYSQL_ROWS     *data_cursor;         /**< current row in cached result */
  /* copy of mysql->affected_rows after statement execution */
  my_ulonglong   affected_rows;
  my_ulonglong   insert_id;            /**< copy of mysql->insert_id */
  /*
    mysql_stmt_fetch() calls this function to fetch one row (it's different
    for buffered, unbuffered and cursor fetch).
  */
  int            (*read_row_func)(struct st_mysql_stmt *stmt,
...
};
/*
  This is a standalone comment. The comment is aligned to fit 79 
  characters per line. There is a dot at the end of each sentence.
  Including the last one.
*/
/**
  Initialize SHA1Context.  

  Set initial values in preparation for computing a new SHA1 message digest.
 
  @param[in,out]  context  the context to reset
 
  @return Operation status
    @retval SHA_SUCCESS      OK
    @retval != SHA_SUCCESS   sha error Code
*/
 
int sha1_reset(SHA1_CONTEXT *context)
{
  ...

[edit] Header Files

 #include "my_header.h"

An exception is made for generated files, for example, those generated by Yacc and Lex, since it is not possible to re-write the generators to produce "correct" files.

[edit] Additional suggestions

It is okay to use inline functions are which satisfy most of the following requirements:

if (a() || b() || c())
  error("something went wrong");

However, short-circuit evaluation like that above is not the best method for evaluating options.

my_bool foo(int val)      { return val; } /* Bad. */
int     foo(longlong val) { return val; } /* Bad. */
my_bool foo(int val)      { return test(val); } /* Good. */
int     foo(longlong val) { return test(val); } /* Good. */
if (a == b)
  return 5;
else return 6;

->

if (a == b)
  return 5;
return 6;
int c= 256*2;
bool a= c;          /* a gets 'true' */
my_bool b= c;       /* b gets zero, i.e. 'false': BAD */
my_bool b= test(c); /* b gets 'true': GOOD */

The reason is that the above makes it much harder for the one reading the caller function code to know what is happening and what kind of code the compiler is generating for the call.

c-1101 CC: ERROR File = listener.cc, Line = 187
  "i" has already been declared in the current scope.

    for (int i= 0; i < num_sockets; i++)

[edit] Suggested mode in emacs

(require 'font-lock)
(require 'cc-mode)
(setq global-font-lock-mode t) ;;colors in all buffers that support it
(setq font-lock-maximum-decoration t) ;;maximum color
(c-add-style "MY"
 '("K&R"
     (c-basic-offset . 2)
     (c-comment-only-line-offset . 0)
     (c-offsets-alist . ((statement-block-intro . +)
                         (knr-argdecl-intro . 0)
                         (substatement-open . 0)
                         (label . -)
                         (statement-cont . +)
                         (arglist-intro . c-lineup-arglist-intro-after-paren)
                         (arglist-close . c-lineup-arglist)
                         (innamespace . 0)
                         (inline-open . 0)
                         (statement-case-open . +)
                         ))
     ))

(defun mysql-c-mode-hook ()
  (interactive)
  (require 'cc-mode)
  (c-set-style "MY")
  (setq indent-tabs-mode nil)
  (setq comment-column 48))

(add-hook 'c-mode-common-hook 'mysql-c-mode-hook)

[edit] Basic vim setup

set tabstop=8
set shiftwidth=2
set backspace=2
set softtabstop
set smartindent
set cindent
set cinoptions=g0:0t0c2C1(0f0l1
set expandtab

[edit] Another vim setup

set tabstop=8
set shiftwidth=2
set bs=2
set et
set sts=2
set tw=78
set formatoptions=cqroa1
set cinoptions=g0:0t0c2C1(0f0l1
set cindent

function InsertShiftTabWrapper()
  let num_spaces = 48 - virtcol('.')
  let line = ' '
  while (num_spaces > 0)
    let line = line . ' '
    let num_spaces = num_spaces - 1
  endwhile
  return line
endfunction
" jump to 48th column by Shift-Tab - to place a comment there
inoremap <S-tab> <c-r>=InsertShiftTabWrapper()<cr>
" highlight trailing spaces as errors
let c_space_errors=1

[edit] An example setup for ctags

Put this configuration into your ~/.ctags file:

--c++-kinds=+p
--fields=+iaS
--extra=+q
--langdef=errmsg
--regex-errmsg=/^(ER_[A-Z0-9_]+)/\1/
--langmap=errmsg:(errmsg*.txt),c:+.ic,yacc:+.yy

[edit] C++ Coding Guidelines of NDB storage engine

The mysqld handler part of NDB (ha_ndbcluster.cc, ha_ndbcluster_binlog.cc, etc.) uses the same coding style as the rest of the mysqld code.

The non-mysqld part of NDB code has a long history, and use a multitude of coding styles. When modifying and extending existing source files or modules, the coding style already used in that code should be followed in terms of indentations, naming conventions, etc. For completely new code, the mysqld conventions (with exceptions below) should probably be followed.

Do not do any change to NDB code purely for the sake of changing from one formatting style to another. It just causes merge annoyances and makes patches harder to read, and we do not expect the style to ever become 100% consistent across all of the source code. It is however ok to fix inconsistent style in lines that are changed for other reasons.

One convention that should be followed for all new or modified code, in both mysqld and non-mysqld parts of the code, is that class member variables should be named with lowercase words separated by underscores '_', and pre-fixed with 'm_'. Like this:

    const char *m_my_class_member;

[edit] Braces

if, while, etc *must* always have braces.

eg. Good

    if (a == b)
    {
       dosomething();
    }

Braces should be on separate line like above.

e.g BAD

    if (a == b) {
       dosomething();
    }

Inline methods inside class(struct) is ok to write like below, (i.e opening brace is on same line as function declaration)

    struct A 
    {
       A() {
       }
    }

[edit] Assignment

a = 3; // ok
a= 3; // not ok

[edit] Use of ndbrequire

In the NDB kernel code, the ndbrequire() facility has historically been widely used. However, most of this is now considered misuse, and use of ndbrequire should generally be avoided. Over time, we want to remove most or all ndbrequires.

There are three different classes of ndbrequire() usage, with corresponding replacement as follows:

[edit] DBUG Tags

The full documentation of the DBUG library is in files dbug/user.* in the MySQL source tree. Here are some of the DBUG tags we now use:

Arguments to the function.

Results from the function.

Something that may be interesting.

When something doesn't go the usual route or may be wrong.

When something went wrong.

Write in a loop, that is probably only useful when debugging the loop. These should normally be deleted when you are satisfied with the code and it has been in real use for a while.

Some tags specific to mysqld, because we want to watch these carefully:

Starting/stopping transactions.

info when mysqld is preparing to die.

Print query.

Retrieved from "http://forge.mysql.com/wiki/MySQL_Internals_Coding_Guidelines"

This page has been accessed 39,429 times. This page was last modified 12:18, 25 May 2011.

Find

Browse
MySQLForge
Main Page
Current events
Recent changes
Random page
Help
Edit
Edit this page
Editing help
This page
Discuss this page
Post a comment
Printable version
Context
Page history
What links here
Related changes
My pages
Special pages
New pages
File list
Statistics
Bug reports
More...