This is a collection of my observations about the coding style used in SQLite.
It is illustrated with code fragments from the SQLite source.
Reasons for the style choices are placed in italics, after each rule. Although many of the choices are apparently the personal preferences of D. Richard Hipp, many are required for general C portability to older C compilers, or to maximize the amount of code that can appear on the screen. This style appears to date from the time of 24x80 character displays.
/* ** Each open SQLite database is represented by an instance of the ** following opaque structure. */- Most comments have start and end delimiters on their own lines.
/* ** The version of the SQLite library. */- Even single-line comments at file scope have delimiters on their own lines.
*************************************************************************- Comment separator lines are 73 characters long.
int sqlite_function_type( sqlite *db, /* The database where the function is registered */ const char *zName, /* Name of the function */ int datatype /* The datatype for this function */ );- Function arguments are commented inside the argument list in both the prototype and definition.
pTab->pTrigger = pTrig; /* Re-enable triggers */- Single-line comments are allowed to follow statements on a line.
/* TODO: Do some validity checks on all fields. In particular, ** make sure fields do not contain NULLs. Otherwise we might core ** when attempting to initialize from a corrupt database file. */- Comments inside function bodies are indented to the same level as the code.
/* The SELECT was successfully coded. Set the return code to 0 ** to indicate no errors. */- Multi-line comments wrap at the end (>70 chars) and are written as paragraphs.
* The "step_list" member points to the first element of a linked list * containing the SQL statements specified as the trigger program.- variable names in comments are placed in double quotes.
"sqlite.h"."sqliteInt.h"."sqlite.h" and "sqliteInt.h". These should be included before other SQLite headers.makeheaders is used to automatically generate header files, so these aren't usually created unless necessary./* ** 2001 September 15 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This header file defines the interface that the sqlite page cache ** subsystem. The page cache subsystem reads and writes a file a page ** at a time and provides a journal for rollback. ** ** @(#) $Id: pager.h,v 1.17 2002/08/12 12:29:57 drh Exp $ */- Starts with date in canonical format.
#ifndef _SQLITE_HASH_H_ #define _SQLITE_HASH_H_ #endif /* _SQLITE_HASH_H_ */- Header files use a guard
#ifdef of form _SQLITE_filename_H.
typedef struct Pager Pager;- Headers use an opaque
struct whenever possible. These are declared in the header, but not defined.struct keyword everywhere.sqlite *db; /* database connection */ int rc; /* error return code */ sqlite_func *pfn; /* sqlite user function */ char *zErrMsg; /* error string */ char **pzErrMsg; /* error string return value */Simplified Hungarian Prefixes
int nArg; /* integer */ char *zName; /* zero-terminated string */ void (*xFinalize)(sqlite_func*); /* function pointer */ Pager *pPager; /* pointer */ Pager **ppPager; /* pointer to pointer */Function Names
void sqliteHashClear(Hash*);- Internal function names usually are "camel-case", with no underscores used.
void sqlite_free_table(char **result);- All exported functions use the standard C naming convention -- all lower case, with underscores.
sqlite_".
Those that start with just "sqlite" (no underscore) are internal API functions.SQLite" (note case). This capitalization is
only used for the name of the library itself, not for any code.int sqliteBtreeCreateTable(Btree*, int*); int sqliteBtreeCreateIndex(Btree*, int*); int sqliteBtreeDropTable(Btree*, int); int sqliteBtreeClearTable(Btree*, int);- Internal APIs start with a common prefix that includes the API name.
#define MASTER_NAME "sqlite_master" #define P3_DYNAMIC 1 /* Pointer to a string obtained from sqliteMalloc() */ #define P3_STATIC (-1) /* Pointer to a static string */- Symbolic constant names are upper case with underscores.
#define instead of enum. Portability.#define SQLITE_ISO8859 1- Publicly visible symbols in the main distribution start with
SQLITE_.
#define STK_Null 0x0001 /* Value is NULL */ #define STK_Str 0x0002 /* Value is a string */ #define STK_Int 0x0004 /* Value is an integer */- Symbolic constants for bitflags start with a common, upper case prefix.
#define ARRAYSIZE(X) (sizeof(X)/sizeof(X[0])) #define sqliteHashFirst(H) ((H)->first)- Macro functions are upper case.
typedef struct sqlite sqlite; typedef struct Column Column; typedef struct Table Table;-
struct names exposed in a header file are "camel case".struct sqlite. if( res ){
id->locked = lk;
rc = SQLITE_OK;
}else{
rc = SQLITE_BUSY;
}
- Lines are indented 2 spaces each. No tabs are used. if( /* expression */){
/* multiple statements */
}else
if( /* expression */){
/* multiple statements */
}else
{
/* final case statements */
}
Long sequences of if-else if blocks at outer scope can have their own syntax:else is separated from the following if() by a blank line. if( pBt->inTrans==0 && pBt->pCursor==0 && pBt->page1!=0 ){
- Compound conditional expressions usually aren't split unless they would wrap. if( strcmp(pP1->zMagic,zMagicHeader)!=0 ||
(pP1->iMagic!=MAGIC && swab32(pP1->iMagic)!=MAGIC) ){
- Compound conditional expressions are split with the binary operator at the end of the line. while( isspace(z[++i]) ){}
- Empty statements are denoted with a pair of empty brackets.
"CREATE TABLE sqlite_master(\n"
" type text,\n"
" name text,\n"
" tbl_name text,\n"
" rootpage integer,\n"
" sql text\n"
")"
;
- Constant SQL strings are split onto multiple lines. readability.int sqliteBtreeKey(BtCursor *pCur, int offset, int amt, char *zBuf){
- Function arguments are on one line if they aren't commented inline.Cell *pCell; MemPage *pPage; int nData;- Multiple variable declarations aren't aligned -- a single space separates the type from the variable name.
Cell* pCell). Prevents a coding error -- Cell* a,b; doesn't declare two pointers.if( p==0 ) return 0;- Explicitly test against zero (don't use
!p).NULL. goto fk_end;
...
fk_end:
...
}
- goto labels are never indented. They always start in column 0._end", "_error",
"_exception", "_cleanup", "_exit".
OS_UNIX and OS_WIN are used to separate operating system-specific behavior."os.c" and "os.h", and wrapped in generic functions sqliteOsFnName().int sqliteOsDelete(const char *zFilename){
#if OS_UNIX
unlink(zFilename);
#endif
#if OS_WIN
DeleteFile(zFilename);
#endif
return SQLITE_OK;
}
- Inside an os-dependent section, the os-specific sections are usually duplicated.#else or #elif cases are used. Only explicit #if ostype ... #endif sections.#ifdef blocks.SQLITE_TEST to #ifdef out behavior used only in debugging or testing.tcl test scripts are in directory "\sqlite\test".assert() to check that the library is being used properly. It is used by programmers not familiar with the code, so they should be protected if possible. This also leads to more robust code.static. This keeps the global namespace clean, and is used by makeheaders to decide when to generate a prototype.makeheaders is relied on to automatically generate header files, so these aren't usually created unless necessary.awk, lemon, and tcl are used in building sqlite and its docs, and should be used when they make for cleaner, more maintainable code.