CREATE CHANGEFEED

The CREATE CHANGEFEED statement creates a new changefeed, which provides row-level change subscriptions.

Changefeeds target a whitelist of tables, called the "watched rows." Every change to a watched row is emitted as a record in a configurable format (JSON) to a configurable sink (Kafka or a cloud storage sink).

For more information, see Change Data Capture.

Note:

CREATE CHANGEFEED is an enterprise-only feature. For the core version, see EXPERIMENTAL CHANGEFEED FOR.

Required privileges

Changefeeds can only be created by superusers, i.e., members of the admin role. The admin role exists by default with root as the member.

Synopsis

CREATECHANGEFEEDFORTABLEtable_name,INTOsinkWITHoption=value,

Parameters

ParameterDescription
tablenameThe name of the table (or tables in a comma separated list) to create a changefeed for.
sinkThe location of the configurable sink. The scheme of the URI indicates the type. For more information, see Sink URI below.
option / valueFor a list of available options and their values, see Options below.



### Sink URI


The sink URI follows the basic format of:



  1. '[scheme]://[host]:[port]?[query_parameters]'



The scheme can be kafka or any cloud storage sink.


#### Kafka


Example of a Kafka sink URI:



  1. 'kafka://broker.address.com:9092?topic_prefix=bar&tlsenabled=true&ca_cert=LS0tLS1CRUdJTiBDRVJUSUZ&sasl_enabled=true&sasl_user=petee&sasl_password=bones'



Query parameters include:

ParameterValueDescription
topic_prefixSTRINGAdds a prefix to all topic names.For example, CREATE CHANGEFEED FOR TABLE foo INTO 'kafka://…?topic_prefix=bar' would emit rows under the topic bar_foo instead of foo.
tls_enabled=trueBOOLIf true, enable Transport Layer Security (TLS) on the connection to Kafka. This can be used with a ca_cert (see below).
ca_certSTRINGThe base64-encoded ca_cert file.Note: To encode your ca.cert, run base64 -w 0 ca.cert.
sasl_enabledBOOLIf true, use SASL/PLAIN to authenticate. This requires a sasl_user and sasl_password (see below).
sasl_userSTRINGYour SASL username.
sasl_passwordSTRINGYour SASL password.

Cloud storage sink

New in v19.1: Use a cloud storage sink to deliver changefeed data to OLAP or big data systems without requiring transport via Kafka.

Note:

Currently, cloud storage sinks only work with JSON and emits newline-delimited JSON files.

Example of a cloud storage sink (i.e., AWS S3) URI:

  1. 'experimental-s3://test-s3encryption/test?AWS_ACCESS_KEY_ID=ABCDEFGHIJKLMNOPQ&AWS_SECRET_ACCESS_KEY=LS0tLS1CRUdJTiBDRVJUSUZ'

Note:

The scheme for a cloud storage sink should be prepended with experimental-.

Any of the cloud storages below can be used as a sink:

  1. [scheme]://[host]/[path]?[parameters]
LocationSchemeHostParameters
Amazon S3s3Bucket nameAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN
AzureazureN/A (see Example file URLsAZURE_ACCOUNT_KEY, AZURE_ACCOUNT_NAME
Google Cloud 1gsBucket nameAUTH (optional; can be default, implicit, or specified), CREDENTIALS
HTTP 2httpRemote hostN/A
NFS/Local 3nodelocalEmpty or nodeID 4 (see Example file URLs)N/A
S3-compatible services 5s3Bucket nameAWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, AWS_REGION 6 (optional), AWS_ENDPOINT

Note:

The location parameters often contain special characters that need to be URI-encoded. Use Javascript's encodeURIComponent function or Go language's url.QueryEscape function to URI-encode the parameters. Other languages provide similar functions to URI-encode special characters.

Note:

If your environment requires an HTTP or HTTPS proxy server for outgoing connections, you can set the standard HTTP_PROXY and HTTPS_PROXY environment variables when starting CockroachDB.

  • 1If the AUTH parameter is not specified, the cloudstorage.gs.default.key cluster setting will be used if it is non-empty, otherwise the implicit behavior is used. If the AUTH parameter is implicit, all GCS connections use Google's default authentication strategy. If the AUTH parameter is default, the cloudstorage.gs.default.key cluster setting must be set to the contents of a service account file which will be used during authentication. New in v19.1: If the AUTH parameter is specified, GCS connections are authenticated on a per-statement basis, which allows the JSON key object to be sent in the CREDENTIALS parameter. The JSON key object should be base64-encoded (using the standard encoding in RFC 4648).

  • 2 You can create your own HTTP server with Caddy or nginx. A custom root CA can be appended to the system's default CAs by setting the cloudstorage.http.custom_ca cluster setting, which will be used when verifying certificates from HTTPS URLs.

  • 3 The file system backup location on the NFS drive is relative to the path specified by the —external-io-dir flag set while starting the node. If the flag is set to disabled, then imports from local directories and NFS drives are disabled.

  • 4New in v19.1: The host component of NFS/Local can either be empty or the nodeID. If the nodeID is specified, it is currently ignored (i.e., any node can be sent work and it will look in its local input/output directory); however, the nodeID will likely be required in the future.

  • 5 A custom root CA can be appended to the system's default CAs by setting the cloudstorage.http.custom_ca cluster setting, which will be used when verifying certificates from an S3-compatible service.

  • 6 The AWS_REGION parameter is optional since it is not a required parameter for most S3-compatible services. Specify the parameter only if your S3-compatible service requires it.

Example file URLs

LocationExample
Amazon S3s3://acme-co/employees.sql?AWS_ACCESS_KEY_ID=123&AWS_SECRET_ACCESS_KEY=456
Azureazure://employees.sql?AZURE_ACCOUNT_KEY=123&AZURE_ACCOUNT_NAME=acme-co
Google Cloudgs://acme-co/employees.sql
HTTPhttp://localhost:8080/employees.sql
NFS/Localnodelocal:///employees.sql, nodelocal://2/employees.sql

Options

OptionValueDescription
updatedN/AInclude updated timestamps with each row.If a cursor is provided, the "updated" timestamps will match the MVCC timestamps of the emitted rows, and there is no initial scan. If a cursor is not provided, the changefeed will perform an initial scan (as of the time the changefeed was created), and the "updated" timestamp for each change record emitted in the initial scan will be the timestamp of the initial scan. Similarly, when a backfill is performed for a schema change, the "updated" timestamp is set to the first timestamp for when the new schema is valid.
resolvedINTERVALPeriodically emit resolved timestamps to the changefeed. Optionally, set a minimum duration between emitting resolved timestamps. If unspecified, all resolved timestamps are emitted.Example: resolved='10s'
envelopekey_only / wrappedUse key_only to emit only the key and no value, which is faster if you only want to know when the key changes.Default: envelope=wrapped
cursorTimestampEmits any changes after the given timestamp, but does not output the current state of the table first. If cursor is not specified, the changefeed starts by doing an initial scan of all the watched rows and emits the current value, then moves to emitting any changes that happen after the scan.When starting a changefeed at a specific cursor, the cursor cannot be before the configured garbage collection window (see gc.ttlseconds) for the table you're trying to follow; otherwise, the changefeed will error. With default garbage collection settings, this means you cannot create a changefeed that starts more than 25 hours in the past.cursor can be used to start a new changefeed where a previous changefeed ended.Example: CURSOR=1536242855577149065.0000000000
formatjson / experimental_avroFormat of the emitted record. Currently, support for Avro is limited and experimental. For mappings of CockroachDB types to Avro types, see the table below. Default: format=json.
confluent_schema_registrySchema Registry addressThe Schema Registry address is required to use experimental_avro.

Avro limitations

Currently, support for Avro is limited and experimental. Below is a list of unsupported SQL types and values for Avro changefeeds:

  • Decimals must have precision specified.
  • Decimals with NaN or infinite values cannot be written in Avro.

Note:

To avoid NaN or infinite values, add a CHECK constraint to prevent these values from being inserted into decimal columns.

Avro types

Below is a mapping of CockroachDB types to Avro types:

CockroachDB TypeAvro TypeAvro Logical Type
INTLONG
BOOLBOOLEAN
FLOATDOUBLE
STRINGSTRING
DATEINTDATE
TIMELONGTIME-MICROS
TIMESTAMPLONGTIME-MICROS
TIMESTAMPTZLONGTIME-MICROS
DECIMALBYTESDECIMAL
UUIDSTRING
INETSTRING
JSONBSTRING

Responses

The messages (i.e., keys and values) emitted to a Kafka topic are specific to the envelope. The default format is wrapped, and the output messages are composed of the following:

  • Key: An array always composed of the row's PRIMARY KEY field(s) (e.g., [1] for JSON or {"id":1} for Avro).
  • Value:
    • One of three possible top-level fields:
      • after, which contains the state of the row after the update (or null' for DELETEs).
      • updated, which contains the updated timestamp.
      • resolved, which is emitted for records representing resolved timestamps. These records do not include an "after" value since they only function as checkpoints.
    • For INSERT and UPDATE, the current state of the row inserted or updated.
    • For DELETE, null.
      For example:
StatementResponse
INSERT INTO office_dogs VALUES (1, 'Petee');JSON: [1] {"after": {"id": 1, "name": "Petee"}} Avro: {"id":1} {"id":1,"name":{"string":"Petee"}}
DELETE FROM office_dogs WHERE name = 'Petee'JSON: [1] {"after": null} Avro: {"id":1} {null}

Examples

Create a changefeed connected to Kafka

  1. > CREATE CHANGEFEED FOR TABLE name INTO 'kafka://host:port' WITH updated, resolved;
  1. +--------------------+
  2. | job_id |
  3. +--------------------+
  4. | 360645287206223873 |
  5. +--------------------+
  6. (1 row)

For more information on how to create a changefeed connected to Kafka, see Change Data Capture.

Create a changefeed connected to Kafka using Avro

  1. > CREATE CHANGEFEED FOR TABLE name INTO 'kafka://host:port' WITH format = experimental_avro, confluent_schema_registry = <schema_registry_address>;
  1. +--------------------+
  2. | job_id |
  3. +--------------------+
  4. | 360645287206223873 |
  5. +--------------------+
  6. (1 row)

For more information on how to create a changefeed that emits an Avro record, see Change Data Capture.

Create a changefeed connected to a cloud storage sink

Warning:

This is an experimental feature. The interface and output are subject to change.

  1. > CREATE CHANGEFEED FOR TABLE name INTO 'experimental-scheme://host?parameters' WITH updated, resolved;
  1. +--------------------+
  2. | job_id |
  3. +--------------------+
  4. | 360645287206223873 |
  5. +--------------------+
  6. (1 row)

For more information on how to create a changefeed connected to a cloud storage sink, see Change Data Capture.

Manage a changefeed

Use the following SQL statements to pause, resume, and cancel a changefeed.

Note:

Changefeed-specific SQL statements (e.g., CANCEL CHANGEFEED) will be added in the future.

Pause a changefeed

  1. > PAUSE JOB job_id;

For more information, see PAUSE JOB.

Resume a paused changefeed

  1. > RESUME JOB job_id;

For more information, see RESUME JOB.

Cancel a changefeed

  1. > CANCEL JOB job_id;

For more information, see CANCEL JOB.

Start a new changefeed where another ended

Find the high-water timestamp for the ended changefeed:

  1. > SELECT * FROM crdb_internal.jobs WHERE job_id = <job_id>;
  1. job_id | job_type | ... | high_water_timestamp | error | coordinator_id
  2. +--------------------+------------+ ... +--------------------------------+-------+----------------+
  3. 383870400694353921 | CHANGEFEED | ... | 1537279405671006870.0000000000 | | 1
  4. (1 row)

Use the high_water_timestamp to start the new changefeed:

  1. > CREATE CHANGEFEED FOR TABLE name INTO 'kafka//host:port' WITH cursor = <high_water_timestamp>;

Note that because the cursor is provided, the initial scan is not performed.

See also

Was this page helpful?
YesNo