We welcome contributions to the SQLite Graph Database Extension! This guide will help you get started with development, testing, and submitting contributions.
- GCC 4.8+ or Clang 3.8+
- Make
- Git
- Python 3.7+ (for testing and examples)
- Valgrind (optional, for memory debugging)
-
Fork the repository on GitHub
-
Clone your fork:
git clone https://github.com/agentflare-ai/sqlite-graph.git cd sqlite-graph -
Set up the build environment:
# Build in debug mode make debug # Run tests to verify setup make test
-
Create a feature branch:
git checkout -b feature/your-feature-name
- Make your changes in the appropriate source files
- Build and test frequently:
make clean && make debug make test
- Run specific tests for your changes:
cd build/tests && ./test_cypher_basic
- Check for memory leaks:
valgrind --leak-check=full ./build/tests/test_cypher_basic
We follow SQLite's coding conventions:
- Standard: C99 with GNU extensions (
-std=gnu99) - Indentation: 2 spaces (no tabs)
- Line length: 80 characters maximum
- Naming:
snake_casefor functions,UPPER_CASEfor macros - Comments: ANSI C-89 style (
/* */)
/*
** Add a node to the graph with proper error handling.
** Returns SQLITE_OK on success, error code on failure.
*/
int graphAddNode(GraphVtab *pVtab, sqlite3_int64 iNodeId,
const char *zProperties) {
GraphNode *pNode;
int rc = SQLITE_OK;
/* Validate input parameters */
if( pVtab==NULL || iNodeId<0 ){
return SQLITE_MISUSE;
}
/* Check if node already exists */
pNode = graphFindNode(pVtab, iNodeId);
if( pNode!=NULL ){
return SQLITE_CONSTRAINT;
}
/* Allocate new node structure */
pNode = (GraphNode*)sqlite3_malloc(sizeof(GraphNode));
if( pNode==NULL ){
return SQLITE_NOMEM;
}
/* Initialize node */
memset(pNode, 0, sizeof(GraphNode));
pNode->iNodeId = iNodeId;
/* Copy properties if provided */
if( zProperties!=NULL ){
pNode->zProperties = sqlite3_mprintf("%s", zProperties);
if( pNode->zProperties==NULL ){
sqlite3_free(pNode);
return SQLITE_NOMEM;
}
}
/* Add to graph */
pNode->pNext = pVtab->pNodes;
pVtab->pNodes = pNode;
return SQLITE_OK;
}- Use
sqlite3_malloc()andsqlite3_free()for memory management - Check return values for all function calls
- Use
UNUSED(x)macro for unused parameters - Initialize all variables before use
- Follow SQLite error codes (
SQLITE_OK,SQLITE_NOMEM, etc.) - Use
testcase()macro for boundary conditions
- Include guards: Use
#ifndef FILENAME_H/#define FILENAME_H/#endif - Forward declarations: Use
typedef struct StructName StructName; - Documentation: Document all public functions with SQLite-style comments
Tests are organized by functionality:
test_cypher_basic.c- Basic Cypher operationstest_write_simple.c- Graph modification teststest_algorithms.c- Graph algorithm teststest_performance.c- Performance and stress tests
Use the Unity testing framework:
#include "unity.h"
#include "graph.h"
void setUp(void) {
/* Setup code before each test */
}
void tearDown(void) {
/* Cleanup code after each test */
}
void test_graphAddNode_success(void) {
GraphVtab *pVtab = createTestGraph();
int rc;
rc = graphAddNode(pVtab, 1, "{\"name\": \"Alice\"}");
TEST_ASSERT_EQUAL(SQLITE_OK, rc);
GraphNode *pNode = graphFindNode(pVtab, 1);
TEST_ASSERT_NOT_NULL(pNode);
TEST_ASSERT_EQUAL(1, pNode->iNodeId);
destroyTestGraph(pVtab);
}
void test_graphAddNode_duplicate(void) {
GraphVtab *pVtab = createTestGraph();
int rc;
/* Add first node */
rc = graphAddNode(pVtab, 1, "{\"name\": \"Alice\"}");
TEST_ASSERT_EQUAL(SQLITE_OK, rc);
/* Try to add duplicate */
rc = graphAddNode(pVtab, 1, "{\"name\": \"Bob\"}");
TEST_ASSERT_EQUAL(SQLITE_CONSTRAINT, rc);
destroyTestGraph(pVtab);
}
int main(void) {
UNITY_BEGIN();
RUN_TEST(test_graphAddNode_success);
RUN_TEST(test_graphAddNode_duplicate);
return UNITY_END();
}# Run all tests
make test
# Run specific test
cd build/tests && ./test_cypher_basic
# Run with verbose output
cd build/tests && ./test_cypher_basic -v
# Run with memory checking
valgrind --leak-check=full ./build/tests/test_cypher_basic- Test edge cases: NULL pointers, empty strings, boundary values
- Test error conditions: Memory allocation failures, constraint violations
- Use descriptive test names:
test_function_condition_expectedResult - Clean up resources: Always free allocated memory in tests
- Test both success and failure paths
-
Run the full test suite:
make test -
Check for memory leaks:
make valgrind
-
Verify code style:
# No automated checker yet, review manually -
Update documentation if needed
-
Create a clear commit message:
git commit -m "Add support for graph traversal optimization - Implement breadth-first search with pruning - Add performance tests for large graphs - Update API documentation"
-
Push to your fork:
git push origin feature/your-feature-name
-
Create a pull request with:
- Clear description of changes
- Reference to related issues
- Test results
- Documentation updates
## Description
Brief description of the changes made.
## Related Issues
Closes #123
## Changes Made
- [ ] Added new feature X
- [ ] Fixed bug in Y
- [ ] Updated documentation
## Testing
- [ ] All existing tests pass
- [ ] Added new tests for changes
- [ ] Tested with Valgrind
- [ ] Performance testing completed
## Documentation
- [ ] Updated API documentation
- [ ] Added example code
- [ ] Updated README if neededsqlite-graph/
├── src/ # Source code
│ ├── graph.c # Main extension entry point
│ ├── graph-vtab.c # Virtual table implementation
│ ├── graph-algo.c # Graph algorithms
│ └── cypher/ # Cypher query engine
│ ├── cypher-lexer.c
│ ├── cypher-parser.c
│ └── cypher-executor.c
├── include/ # Header files
│ └── graph.h # Public API
├── tests/ # Test files
│ ├── test_cypher_basic.c
│ └── test_algorithms.c
├── examples/ # Example applications
├── docs/ # Documentation
└── build/ # Build output
src/graph.c: SQLite extension entry point and initializationsrc/graph-vtab.c: Virtual table interface implementationsrc/cypher/: Cypher query language parser and executorsrc/graph-algo.c: Graph algorithms (shortest path, centrality, etc.)include/graph.h: Public API definitions
-
GDB: Standard debugger
gdb ./build/tests/test_cypher_basic (gdb) run (gdb) bt
-
Valgrind: Memory debugging
valgrind --leak-check=full --show-leak-kinds=all ./build/tests/test_cypher_basic
-
AddressSanitizer: Build with sanitizer
export CFLAGS="-g -O1 -fsanitize=address" make clean && make
# Build with debug symbols
make debug
# Build with maximum debugging
export CFLAGS="-g -O0 -DDEBUG -Wall -Wextra"
make clean && make- Memory leaks: Always pair
sqlite3_malloc()withsqlite3_free() - Null pointer dereference: Check pointers before use
- Buffer overflows: Use
snprintf()instead ofsprintf() - Use after free: Set pointers to NULL after freeing
# Run performance tests
cd build/tests && ./test_performance
# Profile with gprof
export CFLAGS="-g -pg"
make clean && make
cd build/tests && ./test_performance
gprof ./test_performance gmon.out > profile.txt- Use appropriate data structures: Hash tables for lookups, linked lists for iteration
- Minimize memory allocations: Reuse buffers when possible
- Cache frequently accessed data: Node/edge counts, schema information
- Use indexes: Label and property indexes for fast queries
- Optimize critical paths: Query execution, graph traversal
#include <time.h>
void benchmark_operation(void) {
clock_t start = clock();
/* Perform operation */
clock_t end = clock();
double time_taken = ((double)(end - start)) / CLOCKS_PER_SEC;
printf("Operation took %f seconds\n", time_taken);
}- Write clear commit messages
- Keep changes focused - one feature per PR
- Add tests for new functionality
- Update documentation as needed
- Respond to feedback promptly
- Check code style and conventions
- Verify test coverage for changes
- Test functionality manually
- Review performance implications
- Provide constructive feedback
For maintainers with write access to create releases:
-
Update VERSION file with the new version number
-
Update CHANGELOG.md with new features and fixes
-
Create the release using one of these methods:
Option A: GitHub UI (Recommended)
- Go to Actions → "Create Release" workflow → "Run workflow"
Option B: Command Line
./scripts/create-release.sh
-
Monitor the release workflow at GitHub Actions
-
Verify the release appears on GitHub Releases page
For detailed instructions, see docs/RELEASE_PROCESS.md.
- GitHub Issues: For bugs and feature requests
- GitHub Discussions: For questions and general discussion
- Code Review: Tag maintainers for review
- Email: For security issues only
By contributing to this project, you agree that your contributions will be licensed under the MIT License.
Thank you for contributing to the AgentFlare AI SQLite Graph Database Extension!