mirror of
https://github.com/MariaDB/server.git
synced 2025-01-15 19:42:28 +01:00
e6df06d40d
Coding standards and PR template now reference `main`.
380 lines
10 KiB
Markdown
380 lines
10 KiB
Markdown
# Coding Standards
|
||
|
||
This is a working document outlining the coding standard for the general MariaDB codebase.
|
||
The document can be found in the 11.0 and newer trees in the root directory as "CODING_STANDARDS.md"
|
||
|
||
It does not cover the coding standards for individual plugins, these should have their own coding standards documentation.
|
||
|
||
## Using Git with the MariaDB codebase
|
||
|
||
### Git commit messages
|
||
|
||
Git commit messages must conform to the 50/72 rule.
|
||
This is a de facto git standard which is automatically enforced by some editors.
|
||
This means:
|
||
|
||
* 50 characters max for the first (description) line (see exception later)
|
||
* A blank line.
|
||
* 72 characters max for every subsequent line.
|
||
|
||
In addition if there is a Jira ticket number, this should be the first thing in the description.
|
||
As an example:
|
||
|
||
```
|
||
MDEV-12345 Fixing Rockwell Turbo Encabulator
|
||
|
||
The new principle involved is that instead of power being generated by
|
||
the relative motion of conductors and fluxes, it’s produced by the
|
||
modial interaction of magneto-reluctance and capacitive diractance.
|
||
```
|
||
|
||
The only explicitly allowed exception to the 50-72 rules is that if the first line can be MDEV-###### title', even if the title would make the line longer than 50 characters.
|
||
|
||
The commit messages are typically rendered in [Markdown format](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax), so markdown formatting is permitted for the message body.
|
||
|
||
### Branch handling
|
||
|
||
When updating your code, please make sure you perform a rebase, not a merge with the latest branch.
|
||
Pull requests should be a simple fast-forward of the branch they are intended to land on.
|
||
|
||
The correct way to rebase (if working on top of 10.11 branch):
|
||
|
||
```sh
|
||
git fetch upstream/10.11 # This assumes upstream is github.com/MariaDB/server
|
||
git rebase upstream/10.11
|
||
git push --force my_branch
|
||
```
|
||
|
||
### Target branch
|
||
|
||
Pull requests should be based against the correct MariaDB version.
|
||
New features should be based against the `main` branch, which is the GitHub default branch.
|
||
Bug fixes should be based against the earliest maintained branch in which the bug can be reproduced.
|
||
The earliest maintained branch is found at https://mariadb.org/about/#maintenance-policy.
|
||
|
||
## Coding Style (C / C++ files)
|
||
|
||
Everyone has a preferred coding style, there is no real correct style for all projects around the world.
|
||
What is important is that we stick to one common style throughout this code base.
|
||
|
||
### Indentation
|
||
|
||
We should use a variant of the [Allman indentation style](https://en.wikipedia.org/wiki/Indentation_style#Allman_style).
|
||
The variation is to use two spaces instead of tabs and has a couple of minor rule changes as below.
|
||
|
||
Allman style specifies that braces associated with a statement should be on the following line with the same indentation and the statements inside the braces are next level indented.
|
||
The closing braces are also on a new line at the same indentation as the original statement.
|
||
|
||
For example:
|
||
|
||
```cpp
|
||
while (x == y)
|
||
{
|
||
something();
|
||
somethingelse();
|
||
}
|
||
finalthing();
|
||
```
|
||
|
||
#### Switch / Case statements
|
||
|
||
For switch / case statements the `case` needs to be inline with the `switch`.
|
||
Preferably switch (expr) should be followed by '{' on the same line to
|
||
make the lineup of 'case:' nice:
|
||
|
||
For example:
|
||
|
||
```cpp
|
||
switch(level) {
|
||
case ERROR:
|
||
sql_print_error("Error: %s", message.c_ptr_safe());
|
||
break;
|
||
case WARNING:
|
||
sql_print_warning("Warning: %s", message.c_ptr_safe());
|
||
break;
|
||
...
|
||
}
|
||
```
|
||
|
||
#### If statements
|
||
|
||
If the `if` statement only executes one line of code it is possible to write the statement without the braces such as this:
|
||
|
||
```cpp
|
||
if (opt_console)
|
||
opt_error_log= 0;
|
||
```
|
||
|
||
Prefer reducing indent level with the use of early return statements (or in special circumstances goto).
|
||
Rather than:
|
||
|
||
```cpp
|
||
if (condition)
|
||
{
|
||
<logic>
|
||
}
|
||
return error_code;
|
||
```
|
||
|
||
Use:
|
||
|
||
```cpp
|
||
if (!condition)
|
||
return error_code;
|
||
<logic>
|
||
return success;
|
||
```
|
||
|
||
#### Functions
|
||
|
||
Consecutive functions should be separated with 2 empty lines in between
|
||
|
||
```cpp
|
||
void my_function_1()
|
||
{
|
||
<logic>
|
||
}
|
||
|
||
|
||
void my_function_2()
|
||
{
|
||
<logic>
|
||
}
|
||
```
|
||
|
||
#### Preprocessor directives
|
||
|
||
Compiler preprocessor directives should have no indentation to them, even if in the middle of indented code.
|
||
For example:
|
||
|
||
```c
|
||
case SSL_TYPE_NONE: // SSL is not required
|
||
if (opt_require_secure_transport)
|
||
{
|
||
enum enum_vio_type type= vio_type(vio);
|
||
#ifdef HAVE_OPENSSL
|
||
return type != VIO_TYPE_SSL &&
|
||
#ifndef _WIN32
|
||
type != VIO_TYPE_SOCKET;
|
||
#else
|
||
type != VIO_TYPE_NAMEDPIPE;
|
||
#endif
|
||
#else
|
||
#ifndef _WIN32
|
||
return type != VIO_TYPE_SOCKET;
|
||
#else
|
||
return type != VIO_TYPE_NAMEDPIPE;
|
||
#endif
|
||
#endif
|
||
}
|
||
```
|
||
|
||
Comments reflecting the original `#if` condition can be appended to `#else` / `#endif` to provide additional clarity. This can be useful for large code blocks between the start and end preprocessor directives or nested preprocessor directives.
|
||
For example:
|
||
|
||
```c
|
||
#ifndef EMBEDDED_LIBRARY
|
||
...
|
||
#else /* ! EMBEDDED_LIBRARY */
|
||
...
|
||
#endif /* ! EMBEDDED_LIBRARY */
|
||
```
|
||
|
||
### File names
|
||
|
||
File names should be lower case with underscore word separators.
|
||
C file names use the `.c` extension, C++ files use the `.cc` extension and header files use the `.h` extension.
|
||
|
||
### Language standards
|
||
|
||
For pure-C files we use C99 and for C++ we use C++11.
|
||
The code need to be able to compile on multiple platforms using different compilers (for example: Windows / Linux, x86_64 / ARM).
|
||
|
||
### Line lengths
|
||
|
||
Lines should be no more than 80 characters.
|
||
The reason for this is that it makes it easier to have multiple editor
|
||
windows open side by side and still keep code readable without line
|
||
wraps.
|
||
|
||
When breaking long lines:
|
||
- use '()' to group expressions so that the editor can automatically help
|
||
you with the indentation.
|
||
- When breaking expressions, leave the operator (+,- etc) last on the previous
|
||
line.
|
||
|
||
```cpp
|
||
rows= tab->table->file->multi_range_read_info(tab->ref.key, 10, 20, tab->ref.key_parts, &bufsz, &flags, &cost);
|
||
->
|
||
rows= tab->table->file->multi_range_read_info(tab->ref.key, 10, 20,
|
||
tab->ref.key_parts, &bufsz,
|
||
&flags, &cost);
|
||
```
|
||
|
||
```cpp
|
||
tmp= aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
|
||
->
|
||
tmp= (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa+
|
||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb);
|
||
```
|
||
|
||
### Comments
|
||
|
||
Single line / inline code comments can use the double slash (`//`) style of coding, whereas multi-line code comments should use `/*` as a start and `*/` at the end, with the text indented by 2 spaces, for example:
|
||
|
||
```cpp
|
||
/*
|
||
This is a multi-line code comment.
|
||
It has an indentation of two spaces.
|
||
*/
|
||
```
|
||
|
||
### Variables classes, and functions
|
||
|
||
Variables and functions should be descriptive and in "snake case", for example:
|
||
|
||
```cpp
|
||
void my_function(uint16 variable_name)
|
||
{
|
||
```
|
||
|
||
Class names should also be "snake case" but should start with an upper-case character.
|
||
Such as this:
|
||
|
||
```cpp
|
||
class Buffered_logs
|
||
{
|
||
```
|
||
|
||
Assignments should not have a space on the left side of the equals, and one space on the right hand side. For example:
|
||
|
||
```cpp
|
||
a= 1; // Correct
|
||
a = 1; // Incorrect for the server code,
|
||
// ok for Storage Engines if they use it (aka Connect)
|
||
```
|
||
|
||
The above makes it easy to use 'grep' to find all assignments to a variable.
|
||
|
||
Please do not write conditions like this:
|
||
|
||
```cpp
|
||
if (0 == *error_code)
|
||
```
|
||
|
||
Please do this instead:
|
||
|
||
```cpp
|
||
if (*error_code == 0)
|
||
// Or even better
|
||
if (!*error_code)
|
||
```
|
||
|
||
Only use one-character variables (i,j,k...) in short loops. For anything else
|
||
use descriptive names!
|
||
|
||
### Variable declarations
|
||
|
||
Variables should be declared at the start of it's context (start of function, inside the 'if' statement.
|
||
|
||
The benefits of this:
|
||
- Code lines gets shorter
|
||
- It is easier to see the stack space used by a function.
|
||
- It is easier to find the declaration of the variable.
|
||
- If one has to add an 'if (error) goto end' construct, one can do
|
||
that without having to move variable declarations around.
|
||
|
||
|
||
### Variable initializations
|
||
Variables can be initialized using assignment operator or initializer and expression list.
|
||
For Example:
|
||
|
||
```cpp
|
||
int milliseconds= 1000;
|
||
char type= 't';
|
||
```
|
||
|
||
Or
|
||
|
||
```cpp
|
||
int milliseconds{1000};
|
||
char type{'t'};
|
||
```
|
||
|
||
|
||
### Constant integers
|
||
|
||
Constant integers that are used to define elements such as buffer sizes should be defined rather than used directly.
|
||
This is because the integer could change and uses of it could be missed.
|
||
For example:
|
||
|
||
```cpp
|
||
char *buffer= my_malloc(PSI_INSTRUMENT_ME, 1024, MYF(MY_WME));
|
||
|
||
snprint(buffer, 1024, "%d: %s", integer, text);
|
||
```
|
||
|
||
Could become:
|
||
|
||
```cpp
|
||
constexpr int buffer_size= 1024;
|
||
char *buffer= my_malloc(PSI_INSTRUMENT_ME, buffer_size, MYF(MY_WME));
|
||
|
||
snprint(buffer, buffer_size, "%d: %s", integer, text);
|
||
```
|
||
|
||
Alternatively the integer can be defined using an `enum` or `#define`.
|
||
|
||
### Spacing
|
||
|
||
#### Whitespace
|
||
|
||
* Lines should not have any trailing whitespace.
|
||
* There should not be any trailing blank lines at the end of a file.
|
||
* Line endings are POSIX style (`\n`).
|
||
* Two spaces for each indentation level, not tabs.
|
||
|
||
#### Pointers
|
||
|
||
The `*` of a pointer should be on the side of the variable name such as:
|
||
|
||
```cpp
|
||
void my_function(THD *thd)
|
||
{
|
||
```
|
||
|
||
As yet there is no standard as to whether the `*` in a casting should have a space or not.
|
||
Both of these are valid:
|
||
|
||
```cpp
|
||
name= (const char*)db_name;
|
||
name= (const char *) db_name;
|
||
```
|
||
|
||
#### Function variables
|
||
|
||
There should be a space after each comma in a definition and usage of a function.
|
||
For example:
|
||
|
||
```cpp
|
||
my_function(thd, db_name);
|
||
```
|
||
|
||
### Types
|
||
|
||
In general the usage of types such as `char`, `int` and `long` should be discouraged but there are shortened versions of the unsigned variants available for these in `my_global.h`.
|
||
They can be different sizes across platforms and `char` can be either unsigned or signed depending on platform, and therefore are not portable.
|
||
Instead these should be used as appropriate:
|
||
|
||
* 8-bit signed / unsigned int -> `int8` / `uint8`
|
||
* 16-bit signed / unsigned int -> `int16` / `uint16`
|
||
* 32-bit signed / unsigned int -> `int32` / `uint32`
|
||
* 64-bit signed / unsigned int -> `int64` / `uint64`
|
||
* Integer file descriptor -> `File`
|
||
* Integer socket descriptor -> `my_socket`
|
||
|
||
`size_t` and `ptrdiff_t` are used in the source where appropriate, buffer sizes for example.
|
||
It should be noted that these are implementation dependent but are useful when used in the correct context.
|
||
|
||
Further types can be found in the `include/` directory files.
|
||
There are also general utility functions in `mysys`.
|