## 1. Project Overview & Quickstart (timescale/timescaledb)

## File: README.md

<h3>TimescaleDB is a PostgreSQL extension for high-performance real-time analytics on time-series and event data</h3>

[](https://docs.tigerdata.com/)
[](https://timescaledb.slack.com/archives/C4GT3N90X)
[](https://console.cloud.timescale.com/signup)



## Quick Start with TimescaleDB

Get started with TimescaleDB in under 10 minutes. This guide will help you run TimescaleDB locally, create your first hypertable with columnstore enabled, write data to the columnstore, and see instant analytical query performance.

### What You'll Learn

- How to run TimescaleDB with a one-line install or Docker command
- How to create a hypertable with columnstore enabled
- How to insert data directly to the columnstore 
- How to execute analytical queries

### Prerequisites

- Docker installed on your machine
- 8GB RAM recommended
- `psql` client (included with PostgreSQL) or any PostgreSQL client like [pgAdmin](https://www.pgadmin.org/download/)

### Step 1: Start TimescaleDB

You have two options to start TimescaleDB:

#### Option 1: One-line install (Recommended)

The easiest way to get started:

> **Important:** This script is intended for local development and testing only. Do **not** use it for production deployments. For production-ready installation options, see the [TimescaleDB installation guide](https://docs.timescale.com/self-hosted/latest/install/).

**Linux/Mac:**

```sh
curl -sL https://tsdb.co/start-local | sh
```

This command:
- Downloads and starts TimescaleDB (if not already downloaded)
- Exposes PostgreSQL on port **6543** (a non-standard port to avoid conflicts with other PostgreSQL instances on port 5432)
- Automatically tunes settings for your environment using timescaledb-tune
- Sets up a persistent data volume

#### Option 2: Manual Docker command also used for Windows

Alternatively, you can run TimescaleDB directly with Docker:

```bash
docker run -d --name timescaledb \
    -p 6543:5432 \
    -e POSTGRES_PASSWORD=password \
    timescale/timescaledb-ha:pg18
```

**Note:** We use port **6543** (mapped to container port 5432) to avoid conflicts if you have other PostgreSQL instances running on the standard port 5432.

Wait about 1-2 minutes for TimescaleDB to download & initialize.

### Step 2: Connect to TimescaleDB

Connect using `psql`:

```bash
psql -h localhost -p 6543 -U postgres
# When prompted, enter password: password
```

You should see the PostgreSQL prompt. Verify TimescaleDB is installed:

```sql
SELECT extname, extversion FROM pg_extension WHERE extname = 'timescaledb';
```

Expected output:
```
   extname   | extversion
-------------+------------
 timescaledb | 2.x.x
```

**Prefer a GUI?** If you'd rather use a graphical tool instead of the command line, you can download [pgAdmin](https://www.pgadmin.org/download/) and connect to TimescaleDB using the same connection details (host: `localhost`, port: `6543`, user: `postgres`, password: `password`).

### Step 3: Create Your First Hypertable

Let's create a hypertable for IoT sensor data with columnstore enabled:

```sql
-- Create a hypertable with automatic columnstore
CREATE TABLE sensor_data (
    time TIMESTAMPTZ NOT NULL,
    sensor_id TEXT NOT NULL,
    temperature DOUBLE PRECISION,
    humidity DOUBLE PRECISION,
    pressure DOUBLE PRECISION
) WITH (
    tsdb.hypertable
);
```

`tsdb.hypertable` - Converts this into a TimescaleDB hypertable

See more:

- [About hypertables](https://docs.tigerdata.com/use-timescale/latest/hypertables/)
- [API reference](https://docs.tigerdata.com/api/latest/hypertable/)
- [About columnstore](https://docs.tigerdata.com/use-timescale/latest/compression/about-compression/)
- [Enable columnstore manually](https://docs.tigerdata.com/use-timescale/latest/compression/manual-compression/)
- [API reference](https://docs.tigerdata.com/api/latest/compression/)

### Step 4: Insert Sample Data

Let's add some sample sensor readings:


```sql
-- Enable timing to see time to execute queries
\timing on

-- Insert sample data for multiple sensors
-- SET timescaledb.enable_direct_compress_insert = on to insert data directly to the columnstore (columnnar format for performance)
SET timescaledb.enable_direct_compress_insert = on;
INSERT INTO sensor_data (time, sensor_id, temperature, humidity, pressure)
SELECT
    time,
    'sensor_' || ((random() * 9)::int + 1),
    20 + (random() * 15),
    40 + (random() * 30),
    1000 + (random() * 50)
FROM generate_series(
    NOW() - INTERVAL '90 days',
    NOW(),
    INTERVAL '1 seconds'
) AS time;

-- Once data is inserted into the columnstore we optimize the order and structure 
-- this compacts and orders the data in the chunks for optimal query performance and compression
DO $$
DECLARE ch TEXT;
BEGIN
    FOR ch IN SELECT show_chunks('sensor_data') LOOP
        CALL convert_to_columnstore(ch, recompress := true);
    END LOOP;
END $$;
```

This generates ~7,776,001 readings across 10 sensors over the past 90 days.

Verify the data was inserted:

```sql
SELECT COUNT(*) FROM sensor_data;
```

### Step 5: Run Your First Analytical Queries

Now let's run some analytical queries that showcase TimescaleDB's performance:

```sql
-- Enable query timing to see performance
\timing on

-- Query 1: Average readings per sensor over the last 7 days
SELECT
    sensor_id,
    COUNT(*) as readings,
    ROUND(AVG(temperature)::numeric, 2) as avg_temp,
    ROUND(AVG(humidity)::numeric, 2) as avg_humidity,
    ROUND(AVG(pressure)::numeric, 2) as avg_pressure
FROM sensor_data
WHERE time > NOW() - INTERVAL '7 days'
GROUP BY sensor_id
ORDER BY sensor_id;

-- Query 2: Hourly averages using time_bucket 
-- Time buckets enable you to aggregate data in hypertables by time interval and calculate summary values.
SELECT
    time_bucket('1 hour', time) AS hour,
    sensor_id,
    ROUND(AVG(temperature)::numeric, 2) as avg_temp,
    ROUND(AVG(humidity)::numeric, 2) as avg_humidity
FROM sensor_data
WHERE time > NOW() - INTERVAL '24 hours'
GROUP BY hour, sensor_id
ORDER BY hour DESC, sensor_id
LIMIT 20;

-- Query 3: Daily statistics across all sensors
SELECT
    time_bucket('1 day', time) AS day,
    COUNT(*) as total_readings,
    ROUND(AVG(temperature)::numeric, 2) as avg_temp,
    ROUND(MIN(temperature)::numeric, 2) as min_temp,
    ROUND(MAX(temperature)::numeric, 2) as max_temp
FROM sensor_data
GROUP BY day
ORDER BY day DESC
LIMIT 10;

-- Query 4: Latest reading for each sensor
-- Highlights the value of Skipscan executing in under 100ms without skipscan it takes over 5sec
SELECT DISTINCT ON (sensor_id)
    sensor_id,
    time,
    ROUND(temperature::numeric, 2) as temperature,
    ROUND(humidity::numeric, 2) as humidity,
    ROUND(pressure::numeric, 2) as pressure
FROM sensor_data
ORDER BY sensor_id, time DESC;
```

Notice how fast these analytical queries run, even with aggregations across millions of rows. This is the power of TimescaleDB's columnstore.

### What's Happening Behind the Scenes?

TimescaleDB automatically:
- **Partitions your data** into time-based chunks for efficient querying
- **Write directly to columnstore** using columnar storage (90%+ compression typical) and faster vectorized queries
- **Optimizes queries** by only scanning relevant time ranges and columns
- **Enables time_bucket()** - a powerful function for time-series aggregation

See more:

- [Query data](https://docs.tigerdata.com/use-timescale/latest/query-data/)
- [Write data](https://docs.tigerdata.com/use-timescale/latest/write-data/)
- [About time buckets](https://docs.tigerdata.com/use-timescale/latest/time-buckets/about-time-buckets/)
- [API reference](https://docs.tigerdata.com/api/latest/hyperfunctions/time_bucket/)
- [All TimescaleDB features](https://docs.tigerdata.com/use-timescale/latest/)

### Next Steps

Now that you've got the basics, explore more:

### Create Continuous Aggregates

Continuous aggregates make real-time analytics run faster on very large datasets. They continuously and incrementally refresh a query in the background, so that when you run such query, only the data that has changed needs to be computed, not the entire dataset. This is what makes them different from regular PostgreSQL [materialized views](https://www.postgresql.org/docs/current/rules-materializedviews.html), which cannot be incrementally materialized and have to be rebuilt from scratch every time you want to refresh them.

Let's create a continuous aggregate for hourly sensor statistics:

#### Step 1: Create the Continuous Aggregate

```sql
CREATE MATERIALIZED VIEW sensor_data_hourly
WITH (timescaledb.continuous) AS
SELECT
    time_bucket('1 hour', time) AS hour,
    sensor_id,
    AVG(temperature) AS avg_temp,
    AVG(humidity) AS avg_humidity,
    AVG(pressure) AS avg_pressure,
    MIN(temperature) AS min_temp,
    MAX(temperature) AS max_temp,
    COUNT(*) AS reading_count
FROM sensor_data
GROUP BY hour, sensor_id;
```

This creates a materialized view that pre-aggregates your sensor data into hourly buckets. The view is automatically populated with existing data.

#### Step 2: Add a Refresh Policy

To keep the continuous aggregate up-to-date as new data arrives, add a refresh policy:

```sql
SELECT add_continuous_aggregate_policy(
    'sensor_data_hourly',
    start_offset => INTERVAL '3 hours',
    end_offset => INTERVAL '1 hour',
    schedule_interval => INTERVAL '1 hour'
);
```

This policy:
- Refreshes the continuous aggregate every hour
- Processes data from 3 hours ago up to 1 hour ago (leaving the most recent hour for real-time queries)
- Only processes new or changed data incrementally

#### Step 3: Query the Continuous Aggregate

Now you can query the pre-aggregated data for much faster results:

```sql
-- Get hourly averages for the last 24 hours
SELECT
    hour,
    sensor_id,
    ROUND(avg_temp::numeric, 2) AS avg_temp,
    ROUND(avg_humidity::numeric, 2) AS avg_humidity,
    reading_count
FROM sensor_data_hourly
WHERE hour > NOW() - INTERVAL '24 hours'
ORDER BY hour DESC, sensor_id
LIMIT 50;
```

#### Benefits of Continuous Aggregates

- **Faster queries**: Pre-aggregated data means queries run in milliseconds instead of seconds
- **Incremental refresh**: Only new/changed data is processed, not the entire dataset
- **Automatic updates**: The refresh policy keeps your aggregates current without manual intervention
- **Real-time option**: You can enable real-time aggregation to combine materialized and raw data

#### Try It Yourself

Compare the performance difference:

```sql
-- Query the raw hypertable (slower on large datasets)
\timing on
SELECT
    time_bucket('1 hour', time) AS hour,
    AVG(temperature) AS avg_temp
FROM sensor_data
WHERE time > NOW() - INTERVAL '60 days'
GROUP BY hour
ORDER BY hour DESC
LIMIT 24;

-- Query the continuous aggregate (much faster)
SELECT
    hour,
    avg_temp
FROM sensor_data_hourly
WHERE hour > NOW() - INTERVAL '60 days'
ORDER BY hour DESC
LIMIT 24;
```

Notice how the continuous aggregate query is significantly faster, especially as your dataset grows!

See more:

- [About continuous aggregates](https://docs.tigerdata.com/use-timescale/latest/continuous-aggregates/)
- [API reference](https://docs.tigerdata.com/api/latest/continuous-aggregates/create_materialized_view/)
- [TimescaleDB Documentation](https://docs.timescale.com)
- [Time-series Best Practices](https://docs.timescale.com/use-timescale/latest/schema-management/)
- [Continuous Aggregates](https://docs.timescale.com/use-timescale/latest/continuous-aggregates/)

## Examples

Learn TimescaleDB with complete, standalone examples using real-world datasets. Each example includes sample data and analytical queries.

- **[NYC Taxi Data](docs/getting-started/nyc-taxi/)** - Transportation and location-based analytics
- **[Financial Market Data](docs/getting-started/financial-ticks/)** - Trading and market data analysis
- **[Application Events](docs/getting-started/events-uuidv7/)** - Event logging with UUIDv7

Or try some of our workshops
- **[AI Workshop: EV Charging Station Analysis](https://github.com/timescale/TigerData-Workshops/tree/main/AI-Workshop)** - Integrate PostgreSQL with AI capabilities for managing and analyzing EV charging station data
- **[Time-Series Workshop: Financial Data Analysis](https://github.com/timescale/TigerData-Workshops/tree/main/TimeSeries-Workshop-Finance/)** - Work with cryptocurrency tick data, create candlestick charts

## Want TimescaleDB hosted and managed for you? Try Tiger Cloud

[Tiger Cloud](https://docs.tigerdata.com/getting-started/latest/) is the modern PostgreSQL data platform for all your applications. It enhances PostgreSQL to handle time series, events, real-time analytics, and vector search—all in a single database alongside transactional workloads. You get one system that handles live data ingestion, late and out-of-order updates, and low latency queries, with the performance, reliability, and scalability your app needs. Ideal for IoT, crypto, finance, SaaS, and a myriad other domains, Tiger Cloud allows you to build data-heavy, mission-critical apps while retaining the familiarity and reliability of PostgreSQL. See [our whitepaper](https://docs.tigerdata.com/about/latest/whitepaper/) for a deep dive into Tiger Cloud's architecture and how it meets the needs of even the most demanding applications.

A Tiger Cloud service is a single optimized 100% PostgreSQL database instance that you use as is, or extend with capabilities specific to your business needs. The available capabilities are:

- **Time-series and analytics**: PostgreSQL with TimescaleDB. The PostgreSQL you know and love, supercharged with functionality for storing and querying time-series data at scale for real-time analytics and other use cases. Get faster time-based queries with hypertables, continuous aggregates, and columnar storage. Save on storage with native compression, data retention policies, and bottomless data tiering to Amazon S3.
- **AI and vector**: PostgreSQL with vector extensions. Use PostgreSQL as a vector database with purpose built extensions for building AI applications from start to scale. Get fast and accurate similarity search with the pgvector and pgvectorscale extensions. Create vector embeddings and perform LLM reasoning on your data with the pgai extension.
- **PostgreSQL**: the trusted industry-standard RDBMS. Ideal for applications requiring strong data consistency, complex relationships, and advanced querying capabilities. Get ACID compliance, extensive SQL support, JSON handling, and extensibility through custom functions, data types, and extensions.
All services include all the cloud tooling you'd expect for production use: [automatic backups](https://docs.tigerdata.com/use-timescale/latest/backup-restore/backup-restore-cloud/), [high availability](https://docs.tigerdata.com/use-timescale/latest/ha-replicas/), [read replicas](https://docs.tigerdata.com/use-timescale/latest/ha-replicas/read-scaling/), [data forking](https://docs.tigerdata.com/use-timescale/latest/services/service-management/#fork-a-service), [connection pooling](https://docs.tigerdata.com/use-timescale/latest/services/connection-pooling/), [tiered storage](https://docs.tigerdata.com/use-timescale/latest/data-tiering/), [usage-based storage](https://docs.tigerdata.com/about/latest/pricing-and-account-management/), and much more.

## Check build status

|Linux/macOS|Linux i386|Windows|Coverity|Code Coverage|OpenSSF|
|:---:|:---:|:---:|:---:|:---:|:---:|
|[](https://github.com/timescale/timescaledb/actions/workflows/linux-build-and-test.yaml?query=workflow%3ARegression+branch%3Amain+event%3Aschedule)|[](https://github.com/timescale/timescaledb/actions/workflows/linux-32bit-build-and-test.yaml?query=workflow%3ARegression+branch%3Amain+event%3Aschedule)|[](https://github.com/timescale/timescaledb/actions/workflows/windows-build-and-test.yaml?query=workflow%3ARegression+branch%3Amain+event%3Aschedule)|[](https://scan.coverity.com/projects/timescale-timescaledb)|[](https://codecov.io/gh/timescale/timescaledb)|[](https://www.bestpractices.dev/projects/8012)|

## Get involved

We welcome contributions to TimescaleDB! See [Contributing](https://github.com/timescale/timescaledb/blob/main/CONTRIBUTING.md) and [Code style guide](https://github.com/timescale/timescaledb/blob/main/docs/StyleGuide.md) for details.

## Learn about Tiger Data

Tiger Data is the fastest PostgreSQL for transactional, analytical and agentic workloads. To learn more about the company and its products, visit [tigerdata.com](https://www.tigerdata.com).

## Troubleshooting

#### Docker container won't start

```bash
# Check if container is running
docker ps -a

# View container logs (use the appropriate container name)
# For one-line install:
docker logs timescaledb-ha-pg18-quickstart
# For manual Docker command:
docker logs timescaledb

# Stop and remove existing container
# For one-line install:
docker stop timescaledb-ha-pg18-quickstart && docker rm timescaledb-ha-pg18-quickstart
# For manual Docker command:
docker stop timescaledb && docker rm timescaledb

# Start fresh
# Option 1: Use the one-line install
curl -sL https://tsdb.co/start-local | sh
# Option 2: Use manual Docker command
docker run -d --name timescaledb -p 6543:5432 -e POSTGRES_PASSWORD=password timescale/timescaledb-ha:pg18
```

#### Can't connect with psql

- Verify Docker container is running: `docker ps`
- Check port 6543 isn't already in use: `lsof -i :6543`
- Try using explicit host: `psql -h 127.0.0.1 -p 6543 -U postgres`

#### TimescaleDB extension not found

The `timescale/timescaledb-ha:pg18` image has TimescaleDB pre-installed and pre-loaded. If you see errors, ensure you're using the correct image.

## Clean Up

When you're done experimenting:

#### If you used the one-line install:

```bash
# Stop the container
docker stop timescaledb-ha-pg18-quickstart

# Remove the container
docker rm timescaledb-ha-pg18-quickstart

# Remove the persistent data volume
docker volume rm timescaledb_data

# (Optional) Remove the Docker image
docker rmi timescale/timescaledb-ha:pg18
```

#### If you used the manual Docker command:

```bash
# Stop the container
docker stop timescaledb

# Remove the container
docker rm timescaledb

# (Optional) Remove the Docker image
docker rmi timescale/timescaledb-ha:pg18
```

**Note:** If you created a named volume with the manual Docker command, you can remove it with `docker volume rm <volume_name>`.

---

## File: coccinelle/README.md

This directory contains scripts to check the codebase for defective
programming patterns, eg use after free or not freeing resources.

Coccinelle is a static code analysis program. It uses a semantic patch
language which resembles unified diff output. The semantic patches may
inline python or ocaml code for more advanced use cases.

A coccinelle patch file consists of multiple blocks.
Example block header:
```
@ name @
Expression var1;
Expression var2;
@@
```
The block header may contain variable definitions. It may also contain
required matches or non-matches in previous blocks.
Examples for blocks with required previous matches:
```
@ b2 depends on name @
@@
@ b3 depends on name && !b2 @
@@
```
Variables inside a block can also reference matches from previous blocks.
```
@ b2 depends on name @
Expression name.var1;
@@
```
var1 inside this block will be the match from the `name` block.

- https://github.com/coccinelle/coccinelle
- https://coccinelle.gitlabpages.inria.fr/website/
- https://coccinelle.gitlabpages.inria.fr/website/docs/main_grammar.html

---

## File: coverage/README.md

# Code coverage for TimescaleDB

Code coverage can be enabled for TimescaleDB builds by setting the
option `-DCODECOVEAGE=ON` when running CMake (it is off by
default). This enables the necessary compiler option (`--coverage`) to
generate code coverage statistics and should be enough for CI build
reports using, e.g., `codecov.io`. In addition, local code coverage
reports can be generated with the `lcov` tool, when this tool is
installed on the build system.


## Generating local code coverage data files

A code coverage report is generated in three steps using `lcov`:

1. A pre test baseline run to learn what zero coverage looks like (the
   `coverage_base` target).
2. A post test run to learn the test coverage (the `coverage_test`
   target).
3. A final run to combine the pre test and post test output files into
   a final data file (the `coverage_final` target).

Each of these steps can be run manually using the mentioned targets,
but should happen automatically as part of regular build and test
steps. Optionally, this process can be extended with a filtering step
to ignore certain paths that shouldn't be included in the final
report.

## Producing a HTML-based code coverage report

Once the complete test suite has run (`installcheck` target), it is
possible to produce a HTML-based code coverage report that can be
viewed in a web browser. This is automated by the `coverage` target.
Thus, the complete steps to produce a code coverage report are:

1. `cmake --build`
2. `cmake --build --target installcheck`
3. `cmake --build --target coverage`

---

## File: docs/BuildSource.md

### Building from source

#### Building from source (Unix-based systems)

If you are building from source for **non-development purposes**
(i.e., you want to run TimescaleDB, not submit a patch), you should
**always use a release-tagged commit and not build from `main`**.
See the Releases tab for the latest release.

**Prerequisites**:

- A standard PostgreSQL 15, 16, or 17 installation with development
environment (header files) (e.g., `postgresql-server-dev-17` package
for Linux, Postgres.app for MacOS)
- C compiler (e.g., gcc or clang)
- [CMake](https://cmake.org/) version 3.15 or greater

```bash
git clone git@github.com:timescale/timescaledb.git
cd timescaledb
# Find the latest release and checkout, e.g. for 2.15.0:
git checkout 2.15.0
# Bootstrap the build system
./bootstrap
# To build the extension
cd build && make
# To install
make install
```

Note, if you have multiple versions of PostgreSQL installed you can specify the path to `pg_config`
that should be used by using `./bootstrap -DPG_CONFIG=/path/to/pg_config`.

Please see our [additional configuration instructions](https://docs.timescale.com/self-hosted/latest/install/).

#### Building from source (Windows)

If you are building from source for **non-development purposes**
(i.e., you want to run TimescaleDB, not submit a patch), you should
**always use a release-tagged commit and not build from `main`**.
See the Releases tab for the latest release.

**Prerequisites**:

- A standard [PostgreSQL 15, 16, or 17 64-bit installation](https://www.enterprisedb.com/downloads/postgres-postgresql-downloads#windows)
- OpenSSL for Windows
- Microsoft Visual Studio 2017 with CMake and Git components
- OR Visual Studio 2015/2016 with [CMake](https://cmake.org/) version 3.15 or greater and Git
- Make sure all relevant binaries are in your PATH: `pg_config` and `cmake`

If using Visual Studio 2017 with the CMake and Git components, you
should be able to simply clone the repo and open the folder in
Visual Studio which will take care of the rest.

If you are using an earlier version of Visual Studio, then it can
be built in the following way:
```bash
git clone git@github.com:timescale/timescaledb.git
cd timescaledb

# Find the latest release and checkout, e.g. for 2.15.0:
git checkout 2.15.0
# Bootstrap the build system
bootstrap.bat
# To build the extension from command line
cmake --build ./build --config Release
# To install
cmake --build ./build --config Release --target install

# Alternatively, build in Visual Studio via its built-in support for
# CMake or by opening the generated build/timescaledb.sln solution file.
```

---

## File: docs/MultiNodeDeprecation.md

## Multi-node Deprecation

Multi-node support has been deprecated.
TimescaleDB 2.13 is the last version that will include multi-node support. Multi-node support in 2.13 is available for PostgreSQL 13, 14 and 15.
This decision was not made lightly, and we want to provide a clear understanding of the reasoning behind this change and the path forward.

### Why we are ending multi-node support

We began to work on multi-node support in 2018 and released the first version in 2020 to address the growing
demand for higher scalability in TimescaleDB deployments.
The distributed architecture of multi-node allowed for horizontal scalability of writes and reads to go beyond what a single node could provide. 

While we added many improvements since the initial launch, the architecture of multi-node came with a number of
inherent limitations and challenges that have limited its adoption.
Regrettably, only about 1% of current TimescaleDB deployments utilize multi-node, and the complexity involved in
maintaining this feature has become a significant obstacle.
It’s not an isolated feature that can be kept in the product with very little effort since adding new features required
extra development and testing to ensure they also worked for multi-node.

As we've evolved our single-node product and expanded our cloud offering to serve thousands of customers,
we've identified more efficient solutions to meet the scalability needs of our users.

First, we’ve been able and will continue to make big improvements in the write and read performance of single-node. 
We’ve scaled a single-node deployment to process 2 million inserts per second and have seen performance improvements of 10x for common queries.
You can read a summary of the latest query performance improvements [here](https://www.timescale.com/blog/8-performance-improvements-in-recent-timescaledb-releases-for-faster-query-analytics/).

And second, we are leveraging cloud technologies that have become very mature to provide higher scalability in a more accessible way.
For example, our cloud offering uses object storage to deliver virtually [infinite storage capacity at a very low cost](https://www.timescale.com/blog/scaling-postgresql-for-cheap-introducing-tiered-storage-in-timescale/).

For those reasons, we’ve decided to focus our efforts on improving single-node and leveraging cloud technologies to solve for high scalability and as a result we’ve ended support for multi-node.

### What this means for you

We understand that this change may raise questions, and we are committed to supporting you through the transition.

For current TimescaleDB multi-node users, please refer to our [migration documentation](https://docs.timescale.com/migrate/latest/multi-node-to-timescale-service/)
for a step-by-step guide to transition to a single-node configuration.

Alternatively, you can continue to use multi-node up to version 2.13. However, please be aware that future versions will no longer include this functionality.

If you have any questions or feedback, you can share them in the #multi-node channel in our [community Slack](https://slack.timescale.com/).

---

## File: docs/StyleGuide.md

# TimescaleDB code style guide

Source code should follow the
[PostgreSQL coding conventions](https://www.postgresql.org/docs/current/static/source.html). This
includes
[source formatting](https://www.postgresql.org/docs/current/static/source-format.html)
with 4 column tab spacing and layout rules according to the BSD style.

## SQL and PL/pgSQL style

There is no official SQL or PL/pgSQL style guide for PostgreSQL that
we are aware of, apart from the general spacing and layout rules
above. For now, try to follow the style of the surrounding code when
making modifications. We might develop more stringent guidelines in
the future.

## Error messages

Error messages in TimescaleDB should obey the PostgreSQL
[error message style guide](https://www.postgresql.org/docs/current/static/error-style-guide.html).

## C style

While the PostgreSQL project mandates that
[C code adheres to the C89 standard](https://www.postgresql.org/docs/current/static/source-conventions.html)
with some exceptions, we've chosen to allow many C99 features for the
clarity and convenience they provide. PostgreSQL sticks with C89
mostly for compatibility with many older compilers and platforms, such
as Visual Studio on Windows. Visual Studio should support most of C99
nowadays, however. We might revisit this decision in the future if it
turns out to be a problem for important platforms.

Unfortunately, PostgreSQL does not have a consistent style for naming
of functions, variables and types. This
[mailing-list thread](https://www.postgresql.org/message-id/1221125165.5637.12.camel%40abbas-laptop)
elaborates on the situation. Instead, we've tried our best to develop
a consistent style that roughly follows the style of the PostgreSQL
source code.

### Declarations before code

C99 supports having code before a declaration, similar to C++, and we
also support this in the code. For instance, the following code
follows the guidelines:

```C
void some_function()
{
    prepare();
	int result = fetch();
	...
}
```

### Function and variable names

For clarity and consistency, we've chosen to go with lowercase
under-score separated names for functions and variables. For instance,
this piece of code is correct:

```C
static void
my_function_name(int my_parameter)
{
    int my_variable;
    ...
}
```

while this one is wrong:

```C
static void
MyFunctionName(int myParameter)
{
    int myVariable;
    ...
}
```

### Type declarations

New composite/aggregate types should be typedef'd and use
UpperCamelCase naming. For instance, the following is correct:

```C
typedef struct MyType
{
    ...
} MyType;
```

while the following is wrong:

```C
typedef struct my_type
{
    ...
} my_type;
```

### Modular code and namespacing

When possible, code should be grouped into logical modules. Such modules
typically resemble classes in object-oriented programming (OOP)
languages and should use namespaced function and variable names that
have the module name as prefix. TimescaleDB's [Cache](../src/cache.c)
implementation is a good example of such a module where one would use

```C
void
cache_initialize(Cache *c)
{
    ...
}
```

rather than

```C
void
initialize_cache(Cache *c)
{

}
```

### Object-orientated programming style

Even though C is not an object-oriented programming language, it is
fairly straight-forward to write C code with an OOP flavor. While we
do not mandate that C code has an OOP flavor, we recommend it when it
makes sense (e.g., to achieve modularity and code reuse).

For example, TimescaleDB's [cache.c](../src/cache.c) module can be
seen as a _base class_ with multiple derived _subclasses_, such as
[hypertable_cache.c](../src/hypertable_cache.c) and
[chunk_cache.c](../src/chunk_cache.c). Here's another example of
subclassing using shapes:

```C
typedef struct Shape
{
    int color;
    void (*draw)(Shape *, Canvas *);
} Shape;

void
shape_draw(Shape *shape)
{
    /* open canvas for drawing */
    Canvas *c = canvas_open();

    /* other common shape code */
    ...

    shape->draw(shape, c);

    canvas_close(c);
}

typedef struct Circle
{
    Shape shape;
    float diameter;
} Circle;

Circle blue_circle = {
    .shape = {
        .color = BLUE,
        .draw = circle_draw,
    },
    .diameter = 10.1,
};

void
circle_draw(Shape *shape, Canvas *canvas)
{
    Circle *circle = (Circle *) shape;

    /* draw circle */
    ...
}

```

There are a couple of noteworthy take-aways from this
example.

* Non-static "member" methods should take a pointer to the
object as first argument and be namespaced as described above.
* Derived modules can expand the original type using struct embedding,
in which case the "superclass" should be the first member of the
"subclass", so that one can easily upcast a `Circle` to a `Shape` or,
vice-versa, downcast as in `circle_draw()` above.
* C++-style virtual functions can be implemented with functions
pointers. Good use cases for such functions are module-specific
initialization and cleanup, or function overriding in a subclass.

### Other noteworthy recommendations

* Prefer static allocation and/or stack-allocated variables over
  heap/dynamic allocation when possible. Fortunately, PostgreSQL has a
  nice `MemoryContext` implementation that helps with heap allocation
  when needed.
* Try to minimize the number of included headers in source files,
  especially when header files include other headers. Avoid circular
  header dependencies by predeclaring types (or use struct pointers).


For a general guide to writing C functions in PostgreSQL, you can
review the section on
[C-language functions](https://www.postgresql.org/docs/current/static/xfunc-c.html)
in the PostgreSQL documentation.

## Tools and editors

We require running C code through clang-format before submitting a PR.
This will ensure your code is properly formatted according to our style
(which is similar to the PostgreSQL style but implement in clang-format).
You can run clang-format on all of the TimescaleDB code using `make format`
if you have clang-format (version >= 7) or docker installed.


The following
[Wiki post](https://wiki.postgresql.org/wiki/Developer_FAQ#What.27s_the_formatting_style_used_in_PostgreSQL_source_code.3F)
contains links to style configuration files for various editors.

---

## File: scripts/suppressions/README.md

# Suppressions for Clang Sanitizers #

This folder contains [supression files](https://clang.llvm.org/docs/SanitizerSpecialCaseList.html) for
running timescale using Clang's [AddressSanitizer](https://clang.llvm.org/docs/AddressSanitizer.html)
and [UndefinedBehaviorSanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html), which
we use as part of timescale's regission suite. There are a few places OSs have UB and where postgres
has benign memory leaks, in order to run these sanitizers, we suppress these warning.

For ease of use, we provide a script in [/scripts/test_sanitizers.sh] to run our regression tests with
sanitizers enabled.

---

## File: sql/updates/README.md

## General principles for statements in update/downgrade scripts

1. The `search_path` for these scripts will be locked down to
  `pg_catalog, pg_temp`. Locking down `search_path` happens in
  `header.sql`. Therefore all object references need to be fully
  qualified unless they reference objects from `pg_catalog`.
  Use `@extschema@` to refer to the target schema of the installation
  (resolves to `public` by default).
2. All functions should have explicit `search_path`. Setting explicit
  `search_path` will prevent SQL function inlining for functions and
  transaction control for procedures so for some functions/procedures
  it is acceptable to not have explicit `search_path`. Special care
  needs to be taken with those functions/procedures by either setting
  `search_path` in function body or having only fully qualified object
  references including operators.
3. When generating the install scripts `CREATE OR REPLACE` will be
  changed to `CREATE` to prevent users from precreating extension
  objects. Since we need `CREATE OR REPLACE` for update scripts and
  we don't want to maintain two versions of the sql files containing
  the function definitions we use `CREATE OR REPLACE` in those.
4. When adding or removing columns from catalog tables the tables
  need to be completely rebuilt as the C code relies on the physical
  layout of the tables being the same and must not have dropped
  columns. The catalog tables are mapped to C structs which would break
  with dropped columns.

## Extension updates

This directory contains "modfiles" (SQL scripts) with modifications
that are applied when updating from one version of the extension to
another.

The actual update scripts are compiled from modfiles by concatenating
them with the current source code (which should come at the end of the
resulting update script). Update scripts can "jump" several versions
by using multiple modfiles in order. There are two types of modfiles:

* Transition modfiles named `<from>-<to>.sql`, where `from` and `to`
  indicate the (adjacent) versions transitioning between. Transition
  modfiles are concatenated to form the lineage from an origin version
  to any later version.
* Origin modfiles named <version>.sql, which are included only in
  update scripts that origin at the particular version given in the
  name. So, for instance, `0.7.0.sql` is only included in the script
  moving from `0.7.0` to the current version, but not in, e.g., the
  update script for `0.4.0` to the current version. These files
  typically contain fixes for bugs that are specific to the origin
  version, but are no longer present in the transition modfiles.

Notes on post_update.sql
The scripts in post_update.sql are executed as part of the `ALTER
EXTENSION` stmt.

Note that modfiles that contain no changes need not exist as a
file. Transition modfiles must, however, be listed in the
`CMakeLists.txt` file in the parent directory for an update script to
be built for that version.

## Extension downgrades

You can enable the generation of a downgrade file by setting
`GENERATE_DOWNGRADE_SCRIPT` to `ON`, for example:

```
./bootstrap -DGENERATE_DOWNGRADE_SCRIPT=ON
```

To support downgrades to previous versions of the extension, it is
necessary to execute CMake from a Git repository since the generation
of a downgrade script requires access to the previous version files
that are used to generate an update script. In addition, we only
generate a downgrade script to the immediate preceeding version and
not to any other preceeding versions.

The source and target versions are found in be found in the file
`version.config` file in the root of the source tree, where `version`
is the source version and `previous_version` is the target
version. Note that we have a separate field for the downgrade.

A downgrade file consists of:
- A prolog that is retrieved from the target version.
- A version-specific piece of code that exists on the source version.
- An epilog that is retrieved from the target version.

The prolog consists of the files mentioned in the `PRE_UPDATE_FILES`
variable in the target version of `cmake/ScriptFiles.cmake`.

The version-specific code is found in the source version of the file
`sql/updates/reverse-dev.sql`.

The epilog consists of the files in variables `SOURCE_FILES` and
`POST_UPDATE_FILES`.

Note that, in contrast to update scripts, downgrade scripts are not
built by composing several downgrade scripts into a more extensive
downgrade script. We only build a downgrade script to the immediate
preceeding version. To downgrade multiple versions multiple downgrades
need to be chained.

---

## File: src/adts/README.md

# A Collection of ADTs

This directory contains a collection of Abstract Data Types.
These ADTS are containers that can store data of any other type.
These ADTs use macros as oppossed to void pointers for performance
reasons, as well as for better type safety. This approach to
ADTs follows Postgres convention.

## Vector

A dynamic vector implementation that can store any type. It handles
growing/shrinking the memory for you.

## Bit Array

A dynamic vector to store bits. The API allows appending and iterating
an arbitrary amount of bits. It stores the bits in a vector of uint64
and has methods to serialize/deserialize.

---

## File: src/bgw/README.md

# Background worker jobs

TimescaleDB needs to run multiple background jobs. This module
implements a simple scheduler so that jobs inserted into a jobs table
can be run on a schedule. Each database in an instance runs it's own
scheduler because different databases may run different TimescaleDB
extension versions which may require different scheduler logic.

## Schedules

The scheduler allows you to set a `schedule_interval` for every job.
That defines the interval the scheduler will wait after a job finishes
to start it again, if the job is successful. If the job fails, the
scheduler uses `retry_period` in an exponential backoff to decide when
to run the job again.

## Design

The scheduler itself is a background job that continuously runs and waits
for a time when jobs need to be scheduled. It then launches jobs as new
background workers that it controls through the background worker handle.

Aggregate statistics about a job are kept in the job stat catalog
table.  These statistics include the start and finish times of the
last run of the job as well as whether or not the job succeeded. The
`next_start` is used to figure out when next to run a job after a
scheduler is restarted.

The statistics table also tracks consecutive failures and crashes for
the job which are used for calculating the exponential backoff after a
crash or failure (which is used to set the `next_start` after the
crash/failure). Note also that there is a minimum time after the
database scheduler starts up and a crashed job is restarted. This is
to allow the operator enough time to disable the job if needed.

Note that the number of crashes is an overestimate of the actual
number of crashes for a job. This is so that we are conservative and
never miss a crash and fail to use the appropriate backoff
logic. There is some complexity in ensuring that all crashes are
counted. A crash in Postgres causes *all* processes to quit
immediately therefore we cannot write anything to the database once
any process has crashed. Thus, we must be able to deduce that a crash
occurred from a commit that happened before any crash. We accomplish
this by committing a changes to the stats table before a job starts
and undoing the change after it finishes. If a job crashed, it will be
left in an intermediate state from which we deduce that it could have
been the crashing process.

## Scheduler State Machine

The scheduler implements a state machine for each job.  Each job
starts in the `SCHEDULED` state. As soon as a job starts it enters the
`STARTING` state. If the scheduler determines the job should be
terminated (e.g. it has reached a timeout), it moves the job to a
TERMINATING state. Once a background worker has for a job has stopped,
the job returns to the `SCHEDULED` state.  The states and associated
transitions are as follows.

```ditaa
      +---------+         +--------+
+---> |SCHEDULED+-------> |DISABLED|
|     +----+----+         +--------+
|          |
|          |
|          v
|      +---+----+
+<-----+STARTING|
|      +---+----+
|          |
|          |
|          v
|      +---+-------+
+<-----+TERMINATING|
       +-----------+
```

## Limitations

This first implementation has two limitations:

- The list of jobs to be run is read from the database when the
  scheduler is first started. We do not update this list if the jobs
  table changes.
- There is no prioritization for when to run jobs.

## 2. Official Technical Reference & Guides (timescale/docs)

<h3>Tiger Cloud is the modern Postgres data platform for all your applications. It enhances Postgres to handle time series, events, real-time analytics, and vector search—all in a single database alongside transactional workloads.
</h3>

[](https://www.tigerdata.com/docs/)
[](https://timescaledb.slack.com/archives/C4GT3N90X)
[](https://console.cloud.tigerdata.com/signup)



This repository contains the current source for Tiger Data documentation available at https://www.tigerdata.com/docs/. 

We welcome contributions! You can contribute to Tiger Data documentation in the following ways:

- [Create an issue][docs-issues] in this repository and describe the proposed change. Our doc team takes care of it.
- Update the docs yourself and have your change reviewed and published by our doc team.

## Contribute to the Tiger Data docs

To make the contribution yourself:

1. Get the documentation source:

    - No write access? [Fork this repository][github-fork].
    - Already have a write access? [Clone this repository][github-clone].

2. Create a branch from `latest`, make your changes, and raise a pull request back to `latest`.

3. Sign a Contributor License Agreement (CLA).

   You have to sign the CLA only the first time you raise a PR. This helps to ensure that the community is free to use your contributions.

4. Review your changes.

   The documentation site is generated in a separate private repository using [Gatsby][gatsby]. Once you raise a PR for any branch, GitHub **automatically** generates a preview for your changes and attaches the link in the comments. Any new commits are visible at the same URL. If you don't see the latest changes, try an incognito browser window. Automated builds are not available for PRs from forked repositories.

See the [Contributing guide](CONTRIBUTING.md) for style and language guidance. 

## Learn about Tiger Data


Tiger Data is Postgres made powerful. To learn more about the company and its products, visit [tigerdata.com][tigerdata-home].

[docs-issues]: https://github.com/timescale/docs/issues
[gatsby]: https://www.gatsbyjs.com/
[github-clone]: https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository
[github-fork]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo
[tigerdata-home]: https://www.tigerdata.com