# API Reference

Complete reference for Biscuit index SQL API, functions, and operators.

---


## Extension Management

### CREATE EXTENSION

Creates the Biscuit extension in the current database.

**Syntax**:
```sql
CREATE EXTENSION biscuit [ WITH ] [ SCHEMA schema_name ] [ VERSION version ];
```

**Parameters**:
- `schema_name` - Schema to install extension (default: current schema)
- `version` - Specific version to install (default: latest)

**Example**:
```sql
-- Install in public schema
CREATE EXTENSION biscuit;

-- Install in specific schema
CREATE EXTENSION biscuit SCHEMA extensions;

-- Install specific version
CREATE EXTENSION biscuit VERSION '1.0';
```

**Returns**: Nothing on success

**Errors**:
- `ERROR: extension "biscuit" already exists` - Extension already installed
- `ERROR: could not open extension control file` - Installation files missing

---

### DROP EXTENSION

Removes the Biscuit extension from the database.

**Syntax**:
```sql
DROP EXTENSION [ IF EXISTS ] biscuit [ CASCADE | RESTRICT ];
```

**Parameters**:
- `IF EXISTS` - Don't error if extension doesn't exist
- `CASCADE` - Drop dependent objects (including indexes)
- `RESTRICT` - Refuse if dependent objects exist (default)

**Example**:
```sql
-- Drop extension (fails if indexes exist)
DROP EXTENSION biscuit;

-- Drop extension and all Biscuit indexes
DROP EXTENSION biscuit CASCADE;

-- Drop only if exists
DROP EXTENSION IF EXISTS biscuit CASCADE;
```

**Side Effects**:
- All Biscuit indexes are dropped (with CASCADE)
- Index cache is cleared
- Memory is freed

---

## Index Operations

### CREATE INDEX

Creates a Biscuit index on one or more columns.

**Syntax**:
```sql
CREATE INDEX [ CONCURRENTLY ] [ IF NOT EXISTS ] index_name
    ON table_name
    USING biscuit ( column_name [, ...] )
    [ WITH ( storage_parameter [= value] [, ... ] ) ]
    [ WHERE predicate ];
```

**Parameters**:
- `index_name` - Name of the index to create
- `table_name` - Table to index
- `column_name` - Column(s) to index (1 or more)
- `CONCURRENTLY` - Build without blocking writes
- `IF NOT EXISTS` - Don't error if index exists
- `UNIQUE` - Not supported (will error)
- `WHERE predicate` - Create partial index

**Supported Column Types**:
- `TEXT`, `VARCHAR`, `CHAR` - Direct indexing

**Examples**:

```sql
-- Single column index
CREATE INDEX idx_products_name 
ON products USING biscuit (name);

-- Multi-column index
CREATE INDEX idx_products_search 
ON products USING biscuit (name, sku, category);

-- Concurrent build (non-blocking)
CREATE INDEX CONCURRENTLY idx_products_name 
ON products USING biscuit (name);

-- Partial index (filtered)
CREATE INDEX idx_active_products 
ON products USING biscuit (name)
WHERE status = 'active';
```

---

### DROP INDEX

Removes a Biscuit index.

**Syntax**:
```sql
DROP INDEX [ CONCURRENTLY ] [ IF EXISTS ] index_name [, ...] [ CASCADE | RESTRICT ];
```

**Example**:
```sql
-- Drop index
DROP INDEX idx_products_name;

-- Drop without blocking
DROP INDEX CONCURRENTLY idx_products_name;

-- Drop multiple indexes
DROP INDEX idx_products_name, idx_products_sku;
```

---

### REINDEX

Rebuilds a Biscuit index.

**Syntax**:
```text
REINDEX [ ( option [, ...] ) ] { INDEX | TABLE | SCHEMA | DATABASE | SYSTEM } name;
```

**Example**:
```sql
-- Rebuild single index
REINDEX INDEX idx_products_name;

-- Rebuild all indexes on table
REINDEX TABLE products;

-- Rebuild concurrently (PG14+)
REINDEX INDEX CONCURRENTLY idx_products_name;
```

**When to Reindex**:
- After massive data changes (>50% rows)
- Tombstone count exceeds 5000
- Performance degradation detected
- After pg_upgrade

---

## Query Operators

### LIKE Operator

Pattern matching operator supported by Biscuit indexes.

**Syntax**:
```sql
column_name LIKE pattern [ ESCAPE escape_character ]
```

**Pattern Syntax**:
- `%` - Matches zero or more characters
- `_` - Matches exactly one character
- Other characters match themselves
- Case-sensitive matching

**Examples**:

```sql
-- Prefix match
SELECT * FROM products WHERE name LIKE 'Wireless%';

-- Suffix match
SELECT * FROM products WHERE name LIKE '%Mouse';

-- Substring match
SELECT * FROM products WHERE name LIKE '%gaming%';

-- Underscore wildcard
SELECT * FROM products WHERE sku LIKE 'PROD-____-2024';

-- Exact match
SELECT * FROM products WHERE name LIKE 'Wireless Mouse';

-- Complex pattern
SELECT * FROM products WHERE name LIKE 'Wireless%RGB%Gaming%';

-- With ESCAPE character
SELECT * FROM products WHERE name LIKE 'Price: 100\%' ESCAPE '\';
```

**Performance**: See [Pattern Syntax Guide](patterns.md) for optimization details

---

### NOT LIKE Operator

Negated pattern matching.

**Syntax**:
```sql
column_name NOT LIKE pattern
```

**Example**:
```sql
-- Find products NOT containing "test"
SELECT * FROM products WHERE name NOT LIKE '%test%';
```

---

### ILIKE Operator

Case-insensitive pattern matching is supported by the default `biscuit_ops` operator class, and by `biscuit_ilike_ops` for ILIKE-only columns

**Workaround**:
```sql
-- Create index
CREATE INDEX idx_products
ON products USING biscuit (name);

-- Query 
SELECT * FROM products WHERE name ILIKE '%wireless%';
```

---

### NOT ILIKE Operator

Case-insensitive pattern matching is supported by the default `biscuit_ops` operator class, and by `biscuit_ilike_ops` for ILIKE-only columns

**Workaround**:
```sql
-- Create index
CREATE INDEX idx_products
ON products USING biscuit (name);

-- Query 
SELECT * FROM products WHERE name NOT ILIKE '%wireless%';
```

---

### Multi-Column Queries

Query multiple columns with automatic optimization.

**Syntax**:
```sql
WHERE column1 LIKE pattern1
  AND column2 LIKE pattern2
  AND column3 LIKE pattern3;
```

**Example**:
```sql
-- Automatic predicate reordering
SELECT * FROM products 
WHERE name LIKE '%laptop%'          -- Priority: 50 (substring)
  AND brand LIKE 'Dell%'            -- Priority: 20 (prefix)
  AND category LIKE 'Computer%';    -- Priority: 21 (prefix)

-- Execution order: brand → category → name
```

**Performance**: Biscuit automatically reorders predicates by selectivity for optimal performance.

---

## Build Diagnostic Functions

### biscuit_has_roaring()

Checks if the extension was compiled with CRoaring bitmap support.

**Syntax**:
```sql
biscuit_has_roaring() RETURNS boolean
```

**Parameters**: None

**Returns**: `true` if compiled with Roaring support, `false` otherwise

**Example**:
```sql
-- Check Roaring support
SELECT biscuit_has_roaring();

-- Conditional query
SELECT 
    CASE 
        WHEN biscuit_has_roaring() THEN 'Optimal performance'
        ELSE 'Using fallback implementation'
    END as performance_status;
```

**Performance Impact**:
- `true`: High-performance CRoaring bitmaps 
- `false`: Fallback implementation with high memory footprint

**When to Rebuild**:
If this returns `false`, install CRoaring and rebuild:
```bash
# Debian/Ubuntu
sudo apt-get install libroaring-dev
make clean && make && sudo make install

# macOS
brew install croaring
make clean && make && sudo make install
```

---

### biscuit_version()

Returns the Biscuit extension version string.

**Syntax**:
```sql
biscuit_version() RETURNS text
```

**Parameters**: None

**Returns**: Version string (e.g., `"1.0.0"`)

**Example**:
```sql
-- Get version
SELECT biscuit_version();

-- Check minimum version
SELECT biscuit_version() >= '1.0.0' as meets_requirement;
```

---

### biscuit_roaring_version()

Returns the CRoaring library version if available.

**Syntax**:
```sql
biscuit_roaring_version() RETURNS text
```

**Parameters**: None

**Returns**: 
- Roaring version string (e.g., `"2.0.4"`) if compiled with Roaring
- `NULL` if not compiled with Roaring support

**Example**:
```sql
-- Get Roaring version
SELECT biscuit_roaring_version();

-- Check if Roaring is available
SELECT biscuit_roaring_version() IS NOT NULL as has_roaring;

-- Full version report
SELECT 
    biscuit_version() as extension_version,
    biscuit_roaring_version() as roaring_version,
    CASE 
        WHEN biscuit_roaring_version() IS NOT NULL THEN 'Optimal'
        ELSE 'Fallback'
    END as performance_mode;
```

**Output**:
```
 extension_version | roaring_version | performance_mode
-------------------+-----------------+------------------
 2.1.5            | 2.0.4           | Optimal
```

---

### biscuit_build_info()

Returns detailed build-time configuration information.

**Syntax**:
```sql
biscuit_build_info() RETURNS TABLE (
    feature text,
    enabled boolean,
    description text
)
```

**Parameters**: None

**Returns**: Table with build configuration details

**Columns**:
- `feature` - Feature or library name
- `enabled` - Whether the feature is enabled
- `description` - Detailed description

**Example**:
```sql
-- Get all build information
SELECT * FROM biscuit_build_info();

-- Check specific features
SELECT feature, enabled 
FROM biscuit_build_info() 
WHERE feature = 'CRoaring Bitmaps';

-- Filter enabled features only
SELECT feature, description 
FROM biscuit_build_info() 
WHERE enabled = true;
```

**Output**:
```
      feature       | enabled |              description
--------------------+---------+---------------------------------------
 CRoaring Bitmaps   | t       | High-performance bitmap operations...
 PostgreSQL         | t       | Compiled for PostgreSQL 16.1
```

---

### biscuit_build_info_json()

Returns build configuration as a JSON string for automation and scripting.

**Syntax**:
```sql
biscuit_build_info_json() RETURNS text
```

**Parameters**: None

**Returns**: JSON-formatted string with build information

**Example**:
```sql
-- Get JSON build info
SELECT biscuit_build_info_json();

-- Parse as JSON
SELECT biscuit_build_info_json()::json;

-- Extract specific fields
SELECT 
    (biscuit_build_info_json()::json)->>'version' as version,
    (biscuit_build_info_json()::json)->>'roaring_enabled' as roaring,
    (biscuit_build_info_json()::json)->>'postgres_version' as pg_version;
```

**Output Format**:
```json
{
  "version": "1.0.0",
  "roaring_enabled": true,
  "roaring_version": "2.0.4",
  "postgres_version": "16.1",
  "build_date": "Dec 16 2025 10:30:00"
}
```

**Use Cases**:
- CI/CD validation scripts
- Automated deployment checks
- Monitoring systems
- Version compatibility verification

**Shell Script Example**:
```bash
#!/bin/bash
# Check if Roaring is enabled
ROARING=$(psql -t -c "SELECT (biscuit_build_info_json()::json)->>'roaring_enabled';")

if [ "$ROARING" != "true" ]; then
    echo "Warning: Roaring not enabled. Installing CRoaring..."
    sudo apt-get install libroaring-dev
    make clean && make && sudo make install
fi
```

---

### biscuit_check_config()

Performs a comprehensive configuration health check and provides recommendations.

**Syntax**:
```sql
biscuit_check_config() RETURNS TABLE (
    check_name text,
    status text,
    recommendation text
)
```

**Parameters**: None

**Returns**: Table with configuration checks and recommendations

**Columns**:
- `check_name` - Name of the configuration check
- `status` - Current status with visual indicators
- `recommendation` - Action recommendation

**Example**:
```sql
-- Run full configuration check
SELECT * FROM biscuit_check_config();

-- Check for issues
SELECT * FROM biscuit_check_config() 
WHERE status NOT LIKE '✓%';

-- Save check results
CREATE TABLE biscuit_health_log AS
SELECT now() as checked_at, * 
FROM biscuit_check_config();
```

**Output**:
```
   check_name     |      status       |                recommendation
------------------+-------------------+----------------------------------------------
 Roaring Support  | ✓ Enabled         | Optimal configuration (v2.0.4)
 Extension Ver... | 1.0.0             | Current version
 Active Indexes   | 5                 | Indexes are active
```



### biscuit_index_stats()

Returns detailed statistics about a Biscuit index.

**Syntax**:
```sql
biscuit_index_stats(index_oid regclass) RETURNS text
```

**Parameters**:
- `index_oid` - OID or name of the Biscuit index

**Returns**: Multi-line text report with statistics

**Example**:
```text
-- Get statistics for an index
SELECT biscuit_index_stats('idx_products_name'::regclass);

-- With formatted output
\x
SELECT biscuit_index_stats('idx_products_name'::regclass);
\x
```

**Output Format**:
```
Biscuit Index Statistics (FULLY OPTIMIZED)
==========================================
Index: idx_products_name
Active records: 50000
Total slots: 50245
Free slots: 245
Tombstones: 0
Max length: 128
------------------------
CRUD Statistics:
  Inserts: 50245
  Updates: 1205
  Deletes: 245
------------------------
Active Optimizations:
  ✓ 1. Skip wildcard intersections
  ✓ 2. Early termination on empty
  [... 12 optimizations listed ...]
```

**Metrics Explained**:

| Metric | Description | Ideal Value |
|--------|-------------|-------------|
| Active records | Current valid records | = table row count |
| Total slots | Allocated memory slots | ≥ active records |
| Free slots | Reusable slots from deletes | < 1000 |
| Tombstones | Deleted but not cleaned | < 1000 |
| Inserts | Total insert operations | Monotonic increase |
| Updates | Total update operations | - |
| Deletes | Total delete operations | - |



---

### biscuit_index_memory_size()

Returns the in-memory footprint of a Biscuit index in bytes.

**Syntax**:

```sql
biscuit_index_memory_size(index_oid oid) RETURNS bigint
biscuit_index_memory_size(index_name text) RETURNS bigint
```

**Parameters**:

* `index_oid` — OID of the Biscuit index
* `index_name` — Name of the Biscuit index

**Returns**:
Memory usage in bytes for the specified Biscuit index.

**Example**:

```sql
-- Get memory usage using index OID
SELECT biscuit_index_memory_size('idx_products_name'::regclass::oid);

-- Get memory usage using index name
SELECT biscuit_index_memory_size('idx_products_name');
```

---

### biscuit_size_pretty()

Returns a human-readable representation of the in-memory footprint of a Biscuit index.

**Syntax**:

```sql
biscuit_size_pretty(index_name text) RETURNS text
```

**Parameters**:

* `index_name` — Name of the Biscuit index

**Returns**:
Formatted memory usage (bytes, KB, MB, or GB).

**Example**:

```sql
SELECT biscuit_size_pretty('idx_products_name');
```

**Output Format**:

```
128 MB (134217728 bytes)
```


---

## Diagnostic Views

### biscuit_status

Quick overview of extension status and configuration.

**Definition**:
```sql
biscuit_status
```

**Columns**:
- `version` - Extension version
- `roaring_enabled` - Whether CRoaring is enabled
- `bitmap_implementation` - Current bitmap backend
- `total_indexes` - Number of active Biscuit indexes
- `total_index_size` - Combined size of all indexes

**Example**:
```sql
-- View current status
SELECT * FROM biscuit_status;

-- Monitor status changes
CREATE TABLE biscuit_status_history AS
SELECT now() as timestamp, * FROM biscuit_status;
```

**Output**:
```
 version | roaring_enabled | bitmap_implementation  | total_indexes | total_index_size
---------+-----------------+------------------------+---------------+------------------
 1.0.0   | t               | Optimal (CRoaring)     | 5             | 245 MB
```

---

### biscuit_memory_usage

Displays memory and disk usage for all Biscuit indexes in the current database.

**Definition**:

```sql
biscuit_memory_usage
```

**Columns**:

* `schemaname` — Schema containing the index
* `tablename` — Table on which the index is defined
* `indexname` — Name of the Biscuit index
* `bytes` — In-memory size (bytes)
* `human_readable` — Formatted memory usage
* `disk_size` — On-disk size (`pg_relation_size`)

**Example**:

```sql
-- List all Biscuit indexes with memory usage
SELECT * FROM biscuit_memory_usage;
```

**Usage**:

```sql
-- Identify largest Biscuit indexes in memory
SELECT
    indexname,
    human_readable
FROM biscuit_memory_usage
ORDER BY bytes DESC
LIMIT 5;
```



### Notes

* `pg_relation_size()` and `pg_size_pretty()` report **only the on-disk footprint** of a Biscuit index.
* Biscuit maintains its primary data structures in memory for performance; disk size may significantly underrepresent total runtime usage.
* Reported values reflect the current in-memory state and may change over time.


---

## Configuration Parameters

### Server Parameters

These PostgreSQL parameters affect Biscuit performance:

#### shared_buffers

**Description**: Memory for caching index data

**Syntax**:
```sql
-- In postgresql.conf
shared_buffers = '4GB'

-- Or per session
SET shared_buffers = '4GB';  -- Requires restart
```

**Recommendation**: 25% of system RAM

---

#### work_mem

**Description**: Memory for sorting and bitmap operations

**Syntax**:
```sql
-- In postgresql.conf
work_mem = '256MB'

-- Or per session
SET work_mem = '256MB';
```

**Recommendation**: 
- Small queries: 64MB
- Medium queries: 256MB
- Large queries: 512MB-1GB

---

#### maintenance_work_mem

**Description**: Memory for index building

**Syntax**:
```sql
-- In postgresql.conf
maintenance_work_mem = '1GB'

-- Or for current session
SET maintenance_work_mem = '1GB';
```


---

#### effective_cache_size

**Description**: Hint to planner about available cache

**Syntax**:
```sql
-- In postgresql.conf
effective_cache_size = '12GB'
```

---

#### enable_seqscan

**Description**: Allow/disallow sequential scans

**Syntax**:
```sql
-- Disable sequential scans (testing only!)
SET enable_seqscan = off;

-- Re-enable
SET enable_seqscan = on;
```

**Use Case**: Force index usage during testing

---

#### max_parallel_workers_per_gather

**Description**: Workers for parallel bitmap scans

**Syntax**:
```sql
-- In postgresql.conf
max_parallel_workers_per_gather = 4

-- Or per session
SET max_parallel_workers_per_gather = 4;
```

**Recommendation**: 2-4 for most workloads

---

### Session Parameters

Parameters you can set per connection:

```text
-- Increase work memory for this session
SET work_mem = '512MB';

-- Enable query timing
\timing on

-- Show query plans
SET client_min_messages = INFO;

-- Force index usage (testing)
SET enable_seqscan = off;

-- Enable parallel queries
SET max_parallel_workers_per_gather = 4;

-- Reset all to defaults
RESET ALL;
```


---

## System Views

### pg_index

Check if an index is a Biscuit index:

```sql
SELECT 
    indexrelid::regclass as index_name,
    indrelid::regclass as table_name,
    indnatts as num_columns
FROM pg_index
WHERE indexrelid::regclass::text LIKE '%biscuit%';
```

---

### pg_stat_user_indexes

Monitor index usage:

```sql
SELECT 
    indexrelname,
    idx_scan,
    idx_tup_read,
    idx_tup_fetch,
    pg_size_pretty(pg_relation_size(indexrelid)) as size
FROM pg_stat_user_indexes
WHERE indexrelname LIKE '%biscuit%';
```

---

### pg_indexes

View index definitions:

```sql
SELECT 
    schemaname,
    tablename,
    indexname,
    indexdef
FROM pg_indexes
WHERE indexdef LIKE '%biscuit%';
```

---

## Error Messages

Common errors and solutions:

### ERROR: access method "biscuit" does not exist

**Cause**: Extension not installed

**Solution**:
```sql
CREATE EXTENSION biscuit;
```

---

### ERROR: data type X is not supported for biscuit index

**Cause**: Attempting to index unsupported type

**Solution**: Cast to TEXT or use expression index
```sql
CREATE INDEX idx ON table1 USING biscuit (column::TEXT);
```

---

### ERROR: could not open relation with OID

**Cause**: A stale reference to a dropped or rebuilt index. Index state itself
is WAL-logged and recovered by ordinary crash recovery, so this is not expected
as a consequence of an unclean shutdown.

**Solution**:
```sql
REINDEX INDEX idx_name;
```

---

### WARNING: Biscuit: Index cache miss

**Cause**: Normal - index loaded on first use

**Solution**: No action needed (informational only)


---

### ISSUE: biscuit_has_roaring() returns false

**Symptoms**:
```sql
SELECT biscuit_has_roaring();
-- Returns: false
```

**Diagnosis**:
```sql
SELECT * FROM biscuit_check_config();
-- Shows: Roaring Support | ✗ Disabled | Install CRoaring...
```

**Solution**:
```bash
# Install CRoaring development library
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install libroaring-dev

# Verify installation
dpkg -L libroaring-dev | grep roaring.h

# Rebuild extension
cd /path/to/biscuit
make clean
make
sudo make install

# Restart PostgreSQL
sudo systemctl restart postgresql

# Verify in PostgreSQL
psql -c "DROP EXTENSION biscuit CASCADE;"
psql -c "CREATE EXTENSION biscuit;"
psql -c "SELECT biscuit_has_roaring();"
-- Should return: true
```

## Next Steps

- Learn how it works: [Architecture Guide](architecture.md)
-  Master patterns: [Pattern Syntax](patterns.md)
-  Optimize queries: [Performance Tuning](performance.md)
-  Get help: [FAQ](faq.md)
