mirror of
				https://github.com/MariaDB/server.git
				synced 2025-10-30 10:26:12 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			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 directance.
 | ||
| ```
 | ||
| 
 | ||
| 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);
 | ||
| ```
 | ||
| 
 | ||
| ### Integer types
 | ||
| 
 | ||
| The usage of types `long`  and `unsigned long` (and its `ulong` alias)
 | ||
| in new code is *strongly* discouraged. Its use brings no advantages,
 | ||
| only portability problems between Windows and Unixes. The reason for it is that `long`
 | ||
| appears to be the only standard C/C++ datatype, with [size that differs between mainstream 64bit OSes](https://en.wikipedia.org/wiki/64-bit_computing#64-bit_data_models)
 | ||
| 
 | ||
| Instead of using `long`, use `size_t` and `ptrdiff_t` where appropriate,
 | ||
| buffer sizes for example. For integer socket descriptor use `my_socket`.
 | ||
| 
 | ||
| You may use types with fixed length, int32_t and similar, too. Yet, on all platforms we currently support,
 | ||
| * `char` is 8 bit
 | ||
| * `short` is 16 bit
 | ||
| * `int` is 32bit
 | ||
| * `long long` is 64bit
 | ||
| 
 | ||
| and the above is not likely to change for the decades to come. Those types are safe to use. When using `char`
 | ||
| though, be aware that its signed-ness can depend on compiler flags, so do not assume it can take negative values.
 | 
