<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://www.memcp.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Carli</id>
	<title>MemCP - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://www.memcp.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Carli"/>
	<link rel="alternate" type="text/html" href="https://www.memcp.org/wiki/Special:Contributions/Carli"/>
	<updated>2026-09-14T10:13:12Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.1</generator>
	<entry>
		<id>https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=419</id>
		<title>Benchmark MemCP vs. MariaDB on Wordpress</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=419"/>
		<updated>2026-09-09T21:54:02Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 Carl-Philip Hänsch --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: AGPL-3.0-or-later --&amp;gt;&lt;br /&gt;
= Editing Benchmark MemCP vs. MariaDB on Wordpress =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP makes repeated WordPress database work faster.&#039;&#039;&#039; On current master, MemCP-JIT completes this fixture&#039;s search plus total-count query &#039;&#039;&#039;36.0× faster&#039;&#039;&#039; than MariaDB, its comment count &#039;&#039;&#039;21.1× faster&#039;&#039;&#039;, and its archive query &#039;&#039;&#039;6.2× faster&#039;&#039;&#039;. MemCP-JIT has lower measured warm latency across all seven query shapes in this run.&lt;br /&gt;
&lt;br /&gt;
MemCP speaks the MySQL protocol and can also &#039;&#039;&#039;host PHP directly in the database process&#039;&#039;&#039;. WordPress is our example application: the hosting interface is general purpose and is also intended for MediaWiki and other PHP software. Try MemCP with your PHP hosting and measure the queries your application actually runs.&lt;br /&gt;
&lt;br /&gt;
== MariaDB vs. MemCP vs. MemCP-JIT ==&lt;br /&gt;
&lt;br /&gt;
Measured on master [https://github.com/launix-de/memcp/commit/43d0c81401616fafeeb456b22f4a47d6e25361d6 43d0c8140], including the SQL literal-parameterization improvement in PR #873. All three columns use the same seven WordPress query shapes and data snapshot. These are &#039;&#039;&#039;warm database round trips&#039;&#039;&#039;, not HTTP page-load times. Lower is better.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dataset size:&#039;&#039;&#039; 22,063 rows in wp_posts (including 2,000 generated articles and 20,000 revisions), 14,013 post-metadata rows, 6,001 comments and 503 options. Taxonomy data comprises 175 terms, 175 term-taxonomy entries and 7,701 object-to-taxonomy relationships. These are the measured snapshot&#039;s table counts, not the number of rows returned by each query.&lt;br /&gt;
&lt;br /&gt;
Each value is the median of 11 batch means, each containing 100 complete query executions, after 30 warmups. For SQL_CALC_FOUND_ROWS statements, the measured operation also includes the subsequent SELECT FOUND_ROWS() on the same connection.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Query !! MariaDB (ms) !! MemCP (ms) !! MemCP-JIT (ms) !! MariaDB / JIT !! Result check&lt;br /&gt;
|-&lt;br /&gt;
| Option lookup: siteurl || 0.079 || 0.069 || &#039;&#039;&#039;0.056&#039;&#039;&#039; || 1.39× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| Elementor metadata join + LIMIT || 0.152 || 0.108 || &#039;&#039;&#039;0.079&#039;&#039;&#039; || 1.93× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Taxonomy DISTINCT/join, ordered by name || 0.224 || 0.245 || &#039;&#039;&#039;0.142&#039;&#039;&#039; || 1.58× || Equal&lt;br /&gt;
|-&lt;br /&gt;
| Comment count with join || 3.240 || 0.222 || &#039;&#039;&#039;0.153&#039;&#039;&#039; || 21.14× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| WordPress search + FOUND_ROWS || 30.405 || 1.278 || &#039;&#039;&#039;0.844&#039;&#039;&#039; || 36.01× || Equal; 10 rows&lt;br /&gt;
|-&lt;br /&gt;
| Yoast CAST metadata join + FOUND_ROWS || 0.197 || 0.248 || &#039;&#039;&#039;0.144&#039;&#039;&#039; || 1.37× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Monthly archive DISTINCT || 0.718 || 0.168 || &#039;&#039;&#039;0.116&#039;&#039;&#039; || 6.21× || Equal; 10 rows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Timing values are from master 43d0c8140. Taxonomy result equality (all 15 rows, including their order) was verified separately with [https://github.com/launix-de/memcp/pull/871 PR #871].&lt;br /&gt;
&lt;br /&gt;
The two metadata queries return zero rows on this snapshot. Their times describe proving an empty result, not retrieving a populated plugin workload. Tiny differences in the smallest queries are sensitive to scheduling on this shared development machine. We do not average these seven unrelated query shapes into a single WordPress speedup.&lt;br /&gt;
&lt;br /&gt;
== Host PHP directly: remove a round trip for every small query ==&lt;br /&gt;
&lt;br /&gt;
The optional FrankenPHP dependency supplies the PHP runtime; only MemCP&#039;s own bridge and PDO addon live in this repository. PHP requests use ZTS threads, with OPcache enabled. PHP folders are attached through the existing HTTP handler, alongside the SQL API and dashboard.&lt;br /&gt;
&lt;br /&gt;
With a PHP-enabled build and an external ZTS PHP development installation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
make php PHP_CONFIG=/path/to/zts/php-config&lt;br /&gt;
./memcp-php --no-repl -data /path/to/data --api-port=8098 --mysql-port=3307 --serve=/path/to/php-app lib/main.scm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The application is mounted at /; /dashboard remains available. Scheme code can mount additional applications through servePHP. No WordPress source is bundled into MemCP.&lt;br /&gt;
&lt;br /&gt;
The PDO addon supports authenticated memcp: connections and retains ordinary MySQL wire connections. A mysql: connection to localhost/127.0.0.1 and this MemCP server&#039;s own MySQL port can be routed internally; other destinations continue using their original driver. Both paths require database credentials. WordPress&#039;s use of mysqli is a separate connector question: PDO routing alone is not a claim that every WordPress installation or plugin uses PDO.&lt;br /&gt;
&lt;br /&gt;
A separate microbenchmark measures SELECT 1 inside PHP, using an already established connection. Each round performs 100 warmups and 2,000 measured executions; seven rounds alternate the two transports. The timer includes query(), fetchColumn(), and closeCursor(), but excludes HTTP, connection establishment, and PHP startup. Pdo\Mysql::connect forces the real wire driver for the control, so automatic PDO routing cannot accidentally turn both measurements into RAM calls.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! PHP SELECT 1 transport !! Median of round medians&lt;br /&gt;
|-&lt;br /&gt;
| MySQL wire over local TCP || 37.19 µs&lt;br /&gt;
|-&lt;br /&gt;
| MemCP in-process PDO || &#039;&#039;&#039;11.57 µs&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This removes &#039;&#039;&#039;69% of the measured latency&#039;&#039;&#039;, or 25.61 µs per tiny query. At 100 such queries per request, the arithmetic saving is approximately 2.56 ms; at 1,000 queries it is 25.61 ms. Those are extrapolations, not measured WordPress page-load improvements.&lt;br /&gt;
&lt;br /&gt;
For a workload-specific budgeting example, halving 100–200 µs of overhead would save &#039;&#039;&#039;50–100 µs per call (50%)&#039;&#039;&#039;. Across 100 database calls, that would add up to 5–10 ms per request. Those figures illustrate how small savings accumulate; they were not measured here. The measured transport comparison above is the evidence for this setup; measure your own query mix before assigning a per-request saving.&lt;br /&gt;
&lt;br /&gt;
== Reproducible setup ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Item !! Configuration&lt;br /&gt;
|-&lt;br /&gt;
| Measurement date || 9 September 2026 (Europe/Berlin)&lt;br /&gt;
|-&lt;br /&gt;
| CPU || AMD Ryzen 9 7900X3D, 12 physical cores / 24 logical CPUs&lt;br /&gt;
|-&lt;br /&gt;
| Memory / OS || Approximately 62 GiB RAM; Ubuntu 24.04.4 LTS, x86-64&lt;br /&gt;
|-&lt;br /&gt;
| MemCP || Master 43d0c81401616fafeeb456b22f4a47d6e25361d6; unchanged source for both SQL builds&lt;br /&gt;
|-&lt;br /&gt;
| SQL compiler/toolchain || Patched Go 1.27.0, revision 84fe25ee45468f5e3920c11c24e2bbb926fc3a72; GOEXPERIMENT empty vs. GOEXPERIMENT=jit&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB || 10.11.14; query cache OFF; InnoDB buffer pool 128 MiB&lt;br /&gt;
|-&lt;br /&gt;
| PHP microbenchmark || Same MemCP master, built with Go 1.26.0; PHP 8.5.10 ZTS, Zend Engine 4.5.10, OPcache enabled; FrankenPHP v1.12.7; no Go JIT&lt;br /&gt;
|-&lt;br /&gt;
| SQL client || Python 3.12 / PyMySQL, established TCP connections to 127.0.0.1; complete result fetching; no connection setup timed&lt;br /&gt;
|-&lt;br /&gt;
| Database fixture || Read-only consistent snapshot of wordpress_bench_v2, copied to a separate MemCP database; MariaDB InnoDB vs. MemCP sloppy engine; rebuild before measurements&lt;br /&gt;
|-&lt;br /&gt;
| Measurement order || MariaDB, MemCP, MemCP-JIT; one client, no concurrent query load&lt;br /&gt;
|-&lt;br /&gt;
| Runtime settings || Query-plan cache, autoindexing and normal optimizer enabled; TracePrint and ScanDebugging disabled while timing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This is a warm read comparison, not a matched-memory or durability benchmark. The host is shared with development services; cooperating builds/tests were paused for timing, but CPUs and memory were not reserved or pinned. Autoindexing must have time to activate: the warmup count deliberately exceeds its initial observation threshold. Compiled plans, indexes and maintained group/prejoin structures may all contribute to warm results. Their cold build cost and write-maintenance cost are outside the latency table.&lt;br /&gt;
&lt;br /&gt;
Cold startup and initial automatic structure building are not represented by this table. Both MemCP modes reuse the same freshly imported, rebuilt directory sequentially; persisted structures and OS caches remain available. An earlier preparation pass populated some structures before the final measured run. This is deliberately a warm comparison, not a cold-start A/B test.&lt;br /&gt;
&lt;br /&gt;
=== Fixture ===&lt;br /&gt;
&lt;br /&gt;
The seven captured queries exercise option lookups, plugin metadata, taxonomy joins, comment counts, search and archives. The data is synthetic, with real WordPress query shapes. It is not a million-post or concurrent-production benchmark. The source WordPress installation identifies itself as 7.1; WordPress/PHP rendering does not execute in the SQL matrix, and installed plugin versions are not performance inputs once these exact queries are captured.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Contents !! Rows&lt;br /&gt;
|-&lt;br /&gt;
| wp_posts || Posts, pages, revisions and other post types || 22,063&lt;br /&gt;
|-&lt;br /&gt;
| wp_postmeta || Post metadata || 14,013&lt;br /&gt;
|-&lt;br /&gt;
| wp_comments || Comments || 6,001&lt;br /&gt;
|-&lt;br /&gt;
| wp_options || Site options || 503&lt;br /&gt;
|-&lt;br /&gt;
| wp_terms || Terms (category/tag names) || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_taxonomy || Term assignments to taxonomy types || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_relationships || Object-to-taxonomy relationships || 7,701&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The corpus contains 2,000 varied generated articles across 16 topics and 20,000 revisions. Titles, excerpts and bodies vary; body lengths range from 396 to 6,996 bytes (median 1,763). The search query uses realistic, present in 80 generated articles; the full query also considers other post types. Low-cardinality fields such as status and categories naturally repeat. This version-2 corpus must not be mixed with older version-1 measurements.&lt;br /&gt;
&lt;br /&gt;
== Try MemCP with your PHP hosting ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP is faster on the substantial repeated SQL work measured here. Try it with your own PHP hosting.&#039;&#039;&#039; Start with a copy of your site&#039;s data and replay its frequent queries: counts, searches, archives and plugin joins are useful starting points. Compare complete results and total counts, then measure full uncached HTTP requests and representative writes. You can retain the MySQL wire interface or explore direct PHP hosting to remove transport overhead from many small calls.&lt;br /&gt;
&lt;br /&gt;
WordPress is the example, not the product boundary. The same PHP-folder handler and PDO bridge can host other PHP applications; application and plugin compatibility still needs to be checked for the software you deploy.&lt;br /&gt;
&lt;br /&gt;
== Measurement artifacts and exact queries ==&lt;br /&gt;
&lt;br /&gt;
Local artifact directory: &amp;lt;code&amp;gt;../wordpress-db-lab/measurements/wiki-master-43d0c8140/&amp;lt;/code&amp;gt;. It contains results-master.json (raw batch means and complete query results), php-latency.json (all PHP samples), manifest.json, counts.json, corpus.json, text-parity.json, server logs, and a copied benchmark.py. The SQL runner can be repeated against the same fixture; its WP_BINARY and WP_WORKTREE overrides are for separately labelled candidate checks. Candidate measurements are not included in this master matrix.&lt;br /&gt;
&lt;br /&gt;
Source queries: &amp;lt;code&amp;gt;../wordpress-db-lab/profiles/queries/&amp;lt;/code&amp;gt;. They are reproduced below so that the benchmark shapes, including actual ORDER BY clauses, are unambiguous.&lt;br /&gt;
&lt;br /&gt;
=== Option lookup: siteurl ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-- Copyright (C) 2026 MemCP WordPress lab contributors&lt;br /&gt;
-- SPDX-License-Identifier: AGPL-3.0-or-later&lt;br /&gt;
SELECT option_value FROM wp_options WHERE option_name = &#039;siteurl&#039; LIMIT 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Elementor metadata join + LIMIT ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_elementor_template_type&#039; AND wp_postmeta.meta_value = &#039;landing-page&#039; ) ) AND wp_posts.post_type = &#039;e-landing-page&#039; AND ((wp_posts.post_status &amp;lt;&amp;gt; &#039;trash&#039; AND wp_posts.post_status &amp;lt;&amp;gt; &#039;auto-draft&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Taxonomy DISTINCT/join, ordered by name ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT DISTINCT t.term_id, tr.object_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN (&#039;category&#039;, &#039;post_tag&#039;, &#039;post_format&#039;) AND tr.object_id IN (1, 21993, 21982, 21971, 21960) ORDER BY t.name ASC;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Comment count with join ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM wp_comments LEFT JOIN wp_posts AS wp_posts_to_exclude_reviews ON comment_post_ID = wp_posts_to_exclude_reviews.ID WHERE ( comment_approved = &#039;1&#039; ) AND comment_type NOT IN (&#039;note&#039;) AND comment_type != &#039;order_note&#039; AND comment_type != &#039;webhook_delivery&#039; AND comment_type != &#039;action_log&#039; AND wp_posts_to_exclude_reviews.post_type NOT IN (&#039;product&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WordPress search + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND ( wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN (166) ) ) AND (((wp_posts.post_title LIKE &#039;%realistic%&#039;) OR (wp_posts.post_excerpt LIKE &#039;%realistic%&#039;) OR (wp_posts.post_content LIKE &#039;%realistic%&#039;))) AND ((wp_posts.post_type = &#039;attachment&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;e-floating-buttons&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;page&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;post&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;product&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;))) GROUP BY wp_posts.ID ORDER BY wp_posts.post_title LIKE &#039;%realistic%&#039; DESC, wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Yoast CAST metadata join + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_yoast_wpseo_linkdex&#039; AND CAST(wp_postmeta.meta_value AS SIGNED) BETWEEN &#039;1&#039; AND &#039;40&#039; ) ) AND wp_posts.post_type = &#039;post&#039; AND ((wp_posts.post_status = &#039;publish&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Monthly archive DISTINCT ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM wp_posts WHERE post_type = &#039;post&#039; AND post_status != &#039;auto-draft&#039; AND post_status != &#039;trash&#039; ORDER BY post_date DESC;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=418</id>
		<title>Benchmark MemCP vs. MariaDB on Wordpress</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=418"/>
		<updated>2026-09-09T21:44:50Z</updated>

		<summary type="html">&lt;p&gt;Carli: /* Host PHP directly: remove a round trip for every small query */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 MemCP contributors --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: AGPL-3.0-or-later --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP makes repeated WordPress database work faster.&#039;&#039;&#039; On current master, MemCP-JIT completes this fixture&#039;s search plus total-count query &#039;&#039;&#039;36.0× faster&#039;&#039;&#039; than MariaDB, its comment count &#039;&#039;&#039;21.1× faster&#039;&#039;&#039;, and its archive query &#039;&#039;&#039;6.2× faster&#039;&#039;&#039;. MemCP-JIT has lower measured warm latency across all seven query shapes in this run.&lt;br /&gt;
&lt;br /&gt;
MemCP speaks the MySQL protocol and can also &#039;&#039;&#039;host PHP directly in the database process&#039;&#039;&#039;. WordPress is our example application: the hosting interface is general purpose and is also intended for MediaWiki and other PHP software. Try MemCP with your PHP hosting and measure the queries your application actually runs.&lt;br /&gt;
&lt;br /&gt;
== MariaDB vs. MemCP vs. MemCP-JIT ==&lt;br /&gt;
&lt;br /&gt;
Measured on master [https://github.com/launix-de/memcp/commit/43d0c81401616fafeeb456b22f4a47d6e25361d6 43d0c8140], including the SQL literal-parameterization improvement in PR #873. All three columns use the same seven WordPress query shapes and data snapshot. These are &#039;&#039;&#039;warm database round trips&#039;&#039;&#039;, not HTTP page-load times. Lower is better.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dataset size:&#039;&#039;&#039; 22,063 rows in wp_posts (including 2,000 generated articles and 20,000 revisions), 14,013 post-metadata rows, 6,001 comments and 503 options. Taxonomy data comprises 175 terms, 175 term-taxonomy entries and 7,701 object-to-taxonomy relationships. These are the measured snapshot&#039;s table counts, not the number of rows returned by each query.&lt;br /&gt;
&lt;br /&gt;
Each value is the median of 11 batch means, each containing 100 complete query executions, after 30 warmups. For SQL_CALC_FOUND_ROWS statements, the measured operation also includes the subsequent SELECT FOUND_ROWS() on the same connection.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Query !! MariaDB (ms) !! MemCP (ms) !! MemCP-JIT (ms) !! MariaDB / JIT !! Result check&lt;br /&gt;
|-&lt;br /&gt;
| Option lookup: siteurl || 0.079 || 0.069 || &#039;&#039;&#039;0.056&#039;&#039;&#039; || 1.39× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| Elementor metadata join + LIMIT || 0.152 || 0.108 || &#039;&#039;&#039;0.079&#039;&#039;&#039; || 1.93× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Taxonomy DISTINCT/join, ordered by name || 0.224 || 0.245 || &#039;&#039;&#039;0.142&#039;&#039;&#039; || 1.58× || Equal&lt;br /&gt;
|-&lt;br /&gt;
| Comment count with join || 3.240 || 0.222 || &#039;&#039;&#039;0.153&#039;&#039;&#039; || 21.14× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| WordPress search + FOUND_ROWS || 30.405 || 1.278 || &#039;&#039;&#039;0.844&#039;&#039;&#039; || 36.01× || Equal; 10 rows&lt;br /&gt;
|-&lt;br /&gt;
| Yoast CAST metadata join + FOUND_ROWS || 0.197 || 0.248 || &#039;&#039;&#039;0.144&#039;&#039;&#039; || 1.37× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Monthly archive DISTINCT || 0.718 || 0.168 || &#039;&#039;&#039;0.116&#039;&#039;&#039; || 6.21× || Equal; 10 rows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Timing values are from master 43d0c8140. Taxonomy result equality (all 15 rows, including their order) was verified separately with [https://github.com/launix-de/memcp/pull/871 PR #871].&lt;br /&gt;
&lt;br /&gt;
The two metadata queries return zero rows on this snapshot. Their times describe proving an empty result, not retrieving a populated plugin workload. Tiny differences in the smallest queries are sensitive to scheduling on this shared development machine. We do not average these seven unrelated query shapes into a single WordPress speedup.&lt;br /&gt;
&lt;br /&gt;
== Host PHP directly: remove a round trip for every small query ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP makes repeated WordPress database work faster.&#039;&#039;&#039; On current master, MemCP-JIT completes this fixture&#039;s search plus total-count query &#039;&#039;&#039;36.0× faster&#039;&#039;&#039; than MariaDB, its comment count &#039;&#039;&#039;21.1× faster&#039;&#039;&#039;, and its archive query &#039;&#039;&#039;6.2× faster&#039;&#039;&#039;. MemCP-JIT has lower measured warm latency across all seven query shapes in this run.&lt;br /&gt;
&lt;br /&gt;
MemCP speaks the MySQL protocol and can also &#039;&#039;&#039;host PHP directly in the database process&#039;&#039;&#039;. WordPress is our example application: the hosting interface is general purpose and is also intended for MediaWiki and other PHP software. Try MemCP with your PHP hosting and measure the queries your application actually runs.&lt;br /&gt;
&lt;br /&gt;
== MariaDB vs. MemCP vs. MemCP-JIT ==&lt;br /&gt;
&lt;br /&gt;
Measured on master [https://github.com/launix-de/memcp/commit/43d0c81401616fafeeb456b22f4a47d6e25361d6 43d0c8140], including the SQL literal-parameterization improvement in PR #873. All three columns use the same seven WordPress query shapes and data snapshot. These are &#039;&#039;&#039;warm database round trips&#039;&#039;&#039;, not HTTP page-load times. Lower is better.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dataset size:&#039;&#039;&#039; 22,063 rows in wp_posts (including 2,000 generated articles and 20,000 revisions), 14,013 post-metadata rows, 6,001 comments and 503 options. Taxonomy data comprises 175 terms, 175 term-taxonomy entries and 7,701 object-to-taxonomy relationships. These are the measured snapshot&#039;s table counts, not the number of rows returned by each query.&lt;br /&gt;
&lt;br /&gt;
Each value is the median of 11 batch means, each containing 100 complete query executions, after 30 warmups. For SQL_CALC_FOUND_ROWS statements, the measured operation also includes the subsequent SELECT FOUND_ROWS() on the same connection.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Query !! MariaDB (ms) !! MemCP (ms) !! MemCP-JIT (ms) !! MariaDB / JIT !! Result check&lt;br /&gt;
|-&lt;br /&gt;
| Option lookup: siteurl || 0.079 || 0.069 || &#039;&#039;&#039;0.056&#039;&#039;&#039; || 1.39× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| Elementor metadata join + LIMIT || 0.152 || 0.108 || &#039;&#039;&#039;0.079&#039;&#039;&#039; || 1.93× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Taxonomy DISTINCT/join, ordered by name || 0.224 || 0.245 || &#039;&#039;&#039;0.142&#039;&#039;&#039; || 1.58× || Equal&lt;br /&gt;
|-&lt;br /&gt;
| Comment count with join || 3.240 || 0.222 || &#039;&#039;&#039;0.153&#039;&#039;&#039; || 21.14× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| WordPress search + FOUND_ROWS || 30.405 || 1.278 || &#039;&#039;&#039;0.844&#039;&#039;&#039; || 36.01× || Equal; 10 rows&lt;br /&gt;
|-&lt;br /&gt;
| Yoast CAST metadata join + FOUND_ROWS || 0.197 || 0.248 || &#039;&#039;&#039;0.144&#039;&#039;&#039; || 1.37× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Monthly archive DISTINCT || 0.718 || 0.168 || &#039;&#039;&#039;0.116&#039;&#039;&#039; || 6.21× || Equal; 10 rows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Timing values are from master 43d0c8140. Taxonomy result equality (all 15 rows, including their order) was verified separately with [https://github.com/launix-de/memcp/pull/871 PR #871].&lt;br /&gt;
&lt;br /&gt;
The two metadata queries return zero rows on this snapshot. Their times describe proving an empty result, not retrieving a populated plugin workload. Tiny differences in the smallest queries are sensitive to scheduling on this shared development machine. We do not average these seven unrelated query shapes into a single WordPress speedup.&lt;br /&gt;
&lt;br /&gt;
== Host PHP directly: remove a round trip for every small query ==&lt;br /&gt;
&lt;br /&gt;
The optional FrankenPHP dependency supplies the PHP runtime; only MemCP&#039;s own bridge and PDO addon live in this repository. PHP requests use ZTS threads, with OPcache enabled. PHP folders are attached through the existing HTTP handler, alongside the SQL API and dashboard.&lt;br /&gt;
&lt;br /&gt;
With a PHP-enabled build and an external ZTS PHP development installation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
make php PHP_CONFIG=/path/to/zts/php-config&lt;br /&gt;
./memcp-php --no-repl -data /path/to/data --api-port=8098 --mysql-port=3307 --serve=/path/to/php-app lib/main.scm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The application is mounted at /; /dashboard remains available. Scheme code can mount additional applications through servePHP. No WordPress source is bundled into MemCP.&lt;br /&gt;
&lt;br /&gt;
The PDO addon supports authenticated memcp: connections and retains ordinary MySQL wire connections. A mysql: connection to localhost/127.0.0.1 and this MemCP server&#039;s own MySQL port can be routed internally; other destinations continue using their original driver. Both paths require database credentials. WordPress&#039;s use of mysqli is a separate connector question: PDO routing alone is not a claim that every WordPress installation or plugin uses PDO.&lt;br /&gt;
&lt;br /&gt;
A separate microbenchmark measures SELECT 1 inside PHP, using an already established connection. Each round performs 100 warmups and 2,000 measured executions; seven rounds alternate the two transports. The timer includes query(), fetchColumn(), and closeCursor(), but excludes HTTP, connection establishment, and PHP startup. Pdo\Mysql::connect forces the real wire driver for the control, so automatic PDO routing cannot accidentally turn both measurements into RAM calls.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! PHP SELECT 1 transport !! Median of round medians&lt;br /&gt;
|-&lt;br /&gt;
| MySQL wire over local TCP || 37.19 µs&lt;br /&gt;
|-&lt;br /&gt;
| MemCP in-process PDO || &#039;&#039;&#039;11.57 µs&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This removes &#039;&#039;&#039;69% of the measured latency&#039;&#039;&#039;, or 25.61 µs per tiny query. At 100 such queries per request, the arithmetic saving is approximately 2.56 ms; at 1,000 queries it is 25.61 ms. Those are extrapolations, not measured WordPress page-load improvements.&lt;br /&gt;
&lt;br /&gt;
For a workload-specific budgeting example, halving 100–200 µs of overhead would save &#039;&#039;&#039;50–100 µs per call (50%)&#039;&#039;&#039;. Across 100 database calls, that would add up to 5–10 ms per request. Those figures illustrate how small savings accumulate; they were not measured here. The measured transport comparison above is the evidence for this setup; measure your own query mix before assigning a per-request saving.&lt;br /&gt;
&lt;br /&gt;
== Reproducible setup ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Item !! Configuration&lt;br /&gt;
|-&lt;br /&gt;
| Measurement date || 9 September 2026 (Europe/Berlin)&lt;br /&gt;
|-&lt;br /&gt;
| CPU || AMD Ryzen 9 7900X3D, 12 physical cores / 24 logical CPUs&lt;br /&gt;
|-&lt;br /&gt;
| Memory / OS || Approximately 62 GiB RAM; Ubuntu 24.04.4 LTS, x86-64&lt;br /&gt;
|-&lt;br /&gt;
| MemCP || Master 43d0c81401616fafeeb456b22f4a47d6e25361d6; unchanged source for both SQL builds&lt;br /&gt;
|-&lt;br /&gt;
| SQL compiler/toolchain || Patched Go 1.27.0, revision 84fe25ee45468f5e3920c11c24e2bbb926fc3a72; GOEXPERIMENT empty vs. GOEXPERIMENT=jit&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB || 10.11.14; query cache OFF; InnoDB buffer pool 128 MiB&lt;br /&gt;
|-&lt;br /&gt;
| PHP microbenchmark || Same MemCP master, built with Go 1.26.0; PHP 8.5.10 ZTS, Zend Engine 4.5.10, OPcache enabled; FrankenPHP v1.12.7; no Go JIT&lt;br /&gt;
|-&lt;br /&gt;
| SQL client || Python 3.12 / PyMySQL, established TCP connections to 127.0.0.1; complete result fetching; no connection setup timed&lt;br /&gt;
|-&lt;br /&gt;
| Database fixture || Read-only consistent snapshot of wordpress_bench_v2, copied to a separate MemCP database; MariaDB InnoDB vs. MemCP sloppy engine; rebuild before measurements&lt;br /&gt;
|-&lt;br /&gt;
| Measurement order || MariaDB, MemCP, MemCP-JIT; one client, no concurrent query load&lt;br /&gt;
|-&lt;br /&gt;
| Runtime settings || Query-plan cache, autoindexing and normal optimizer enabled; TracePrint and ScanDebugging disabled while timing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This is a warm read comparison, not a matched-memory or durability benchmark. The host is shared with development services; cooperating builds/tests were paused for timing, but CPUs and memory were not reserved or pinned. Autoindexing must have time to activate: the warmup count deliberately exceeds its initial observation threshold. Compiled plans, indexes and maintained group/prejoin structures may all contribute to warm results. Their cold build cost and write-maintenance cost are outside the latency table.&lt;br /&gt;
&lt;br /&gt;
Cold startup and initial automatic structure building are not represented by this table. Both MemCP modes reuse the same freshly imported, rebuilt directory sequentially; persisted structures and OS caches remain available. An earlier preparation pass populated some structures before the final measured run. This is deliberately a warm comparison, not a cold-start A/B test.&lt;br /&gt;
&lt;br /&gt;
=== Fixture ===&lt;br /&gt;
&lt;br /&gt;
The seven captured queries exercise option lookups, plugin metadata, taxonomy joins, comment counts, search and archives. The data is synthetic, with real WordPress query shapes. It is not a million-post or concurrent-production benchmark. The source WordPress installation identifies itself as 7.1; WordPress/PHP rendering does not execute in the SQL matrix, and installed plugin versions are not performance inputs once these exact queries are captured.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Contents !! Rows&lt;br /&gt;
|-&lt;br /&gt;
| wp_posts || Posts, pages, revisions and other post types || 22,063&lt;br /&gt;
|-&lt;br /&gt;
| wp_postmeta || Post metadata || 14,013&lt;br /&gt;
|-&lt;br /&gt;
| wp_comments || Comments || 6,001&lt;br /&gt;
|-&lt;br /&gt;
| wp_options || Site options || 503&lt;br /&gt;
|-&lt;br /&gt;
| wp_terms || Terms (category/tag names) || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_taxonomy || Term assignments to taxonomy types || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_relationships || Object-to-taxonomy relationships || 7,701&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The corpus contains 2,000 varied generated articles across 16 topics and 20,000 revisions. Titles, excerpts and bodies vary; body lengths range from 396 to 6,996 bytes (median 1,763). The search query uses realistic, present in 80 generated articles; the full query also considers other post types. Low-cardinality fields such as status and categories naturally repeat. This version-2 corpus must not be mixed with older version-1 measurements.&lt;br /&gt;
&lt;br /&gt;
== Try MemCP with your PHP hosting ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP is faster on the substantial repeated SQL work measured here. Try it with your own PHP hosting.&#039;&#039;&#039; Start with a copy of your site&#039;s data and replay its frequent queries: counts, searches, archives and plugin joins are useful starting points. Compare complete results and total counts, then measure full uncached HTTP requests and representative writes. You can retain the MySQL wire interface or explore direct PHP hosting to remove transport overhead from many small calls.&lt;br /&gt;
&lt;br /&gt;
WordPress is the example, not the product boundary. The same PHP-folder handler and PDO bridge can host other PHP applications; application and plugin compatibility still needs to be checked for the software you deploy.&lt;br /&gt;
&lt;br /&gt;
== Measurement artifacts and exact queries ==&lt;br /&gt;
&lt;br /&gt;
Local artifact directory: &amp;lt;code&amp;gt;../wordpress-db-lab/measurements/wiki-master-43d0c8140/&amp;lt;/code&amp;gt;. It contains results-master.json (raw batch means and complete query results), php-latency.json (all PHP samples), manifest.json, counts.json, corpus.json, text-parity.json, server logs, and a copied benchmark.py. The SQL runner can be repeated against the same fixture; its WP_BINARY and WP_WORKTREE overrides are for separately labelled candidate checks. Candidate measurements are not included in this master matrix.&lt;br /&gt;
&lt;br /&gt;
Source queries: &amp;lt;code&amp;gt;../wordpress-db-lab/profiles/queries/&amp;lt;/code&amp;gt;. They are reproduced below so that the benchmark shapes, including actual ORDER BY clauses, are unambiguous.&lt;br /&gt;
&lt;br /&gt;
=== Option lookup: siteurl ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
-- Copyright (C) 2026 MemCP WordPress lab contributors&lt;br /&gt;
-- SPDX-License-Identifier: AGPL-3.0-or-later&lt;br /&gt;
SELECT option_value FROM wp_options WHERE option_name = &#039;siteurl&#039; LIMIT 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Elementor metadata join + LIMIT ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_elementor_template_type&#039; AND wp_postmeta.meta_value = &#039;landing-page&#039; ) ) AND wp_posts.post_type = &#039;e-landing-page&#039; AND ((wp_posts.post_status &amp;lt;&amp;gt; &#039;trash&#039; AND wp_posts.post_status &amp;lt;&amp;gt; &#039;auto-draft&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 1;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Taxonomy DISTINCT/join, ordered by name ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT DISTINCT t.term_id, tr.object_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN (&#039;category&#039;, &#039;post_tag&#039;, &#039;post_format&#039;) AND tr.object_id IN (1, 21993, 21982, 21971, 21960) ORDER BY t.name ASC;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Comment count with join ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM wp_comments LEFT JOIN wp_posts AS wp_posts_to_exclude_reviews ON comment_post_ID = wp_posts_to_exclude_reviews.ID WHERE ( comment_approved = &#039;1&#039; ) AND comment_type NOT IN (&#039;note&#039;) AND comment_type != &#039;order_note&#039; AND comment_type != &#039;webhook_delivery&#039; AND comment_type != &#039;action_log&#039; AND wp_posts_to_exclude_reviews.post_type NOT IN (&#039;product&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WordPress search + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND ( wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN (166) ) ) AND (((wp_posts.post_title LIKE &#039;%realistic%&#039;) OR (wp_posts.post_excerpt LIKE &#039;%realistic%&#039;) OR (wp_posts.post_content LIKE &#039;%realistic%&#039;))) AND ((wp_posts.post_type = &#039;attachment&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;e-floating-buttons&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;page&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;post&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;product&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;))) GROUP BY wp_posts.ID ORDER BY wp_posts.post_title LIKE &#039;%realistic%&#039; DESC, wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Yoast CAST metadata join + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_yoast_wpseo_linkdex&#039; AND CAST(wp_postmeta.meta_value AS SIGNED) BETWEEN &#039;1&#039; AND &#039;40&#039; ) ) AND wp_posts.post_type = &#039;post&#039; AND ((wp_posts.post_status = &#039;publish&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Monthly archive DISTINCT ===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM wp_posts WHERE post_type = &#039;post&#039; AND post_status != &#039;auto-draft&#039; AND post_status != &#039;trash&#039; ORDER BY post_date DESC;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Reproducible setup ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Item !! Configuration&lt;br /&gt;
|-&lt;br /&gt;
| Measurement date || 9 September 2026 (Europe/Berlin)&lt;br /&gt;
|-&lt;br /&gt;
| CPU || AMD Ryzen 9 7900X3D, 12 physical cores / 24 logical CPUs&lt;br /&gt;
|-&lt;br /&gt;
| Memory / OS || Approximately 62 GiB RAM; Ubuntu 24.04.4 LTS, x86-64&lt;br /&gt;
|-&lt;br /&gt;
| MemCP || Master 43d0c81401616fafeeb456b22f4a47d6e25361d6; unchanged source for both SQL builds&lt;br /&gt;
|-&lt;br /&gt;
| SQL compiler/toolchain || Patched Go 1.27.0, revision 84fe25ee45468f5e3920c11c24e2bbb926fc3a72; GOEXPERIMENT empty vs. GOEXPERIMENT=jit&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB || 10.11.14; query cache OFF; InnoDB buffer pool 128 MiB&lt;br /&gt;
|-&lt;br /&gt;
| PHP microbenchmark || Same MemCP master, built with Go 1.26.0; PHP 8.5.10 ZTS, Zend Engine 4.5.10, OPcache enabled; FrankenPHP v1.12.7; no Go JIT&lt;br /&gt;
|-&lt;br /&gt;
| SQL client || Python 3.12 / PyMySQL, established TCP connections to 127.0.0.1; complete result fetching; no connection setup timed&lt;br /&gt;
|-&lt;br /&gt;
| Database fixture || Read-only consistent snapshot of wordpress_bench_v2, copied to a separate MemCP database; MariaDB InnoDB vs. MemCP sloppy engine; rebuild before measurements&lt;br /&gt;
|-&lt;br /&gt;
| Measurement order || MariaDB, MemCP, MemCP-JIT; one client, no concurrent query load&lt;br /&gt;
|-&lt;br /&gt;
| Runtime settings || Query-plan cache, autoindexing and normal optimizer enabled; TracePrint and ScanDebugging disabled while timing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This is a warm read comparison, not a matched-memory or durability benchmark. The host is shared with development services; cooperating builds/tests were paused for timing, but CPUs and memory were not reserved or pinned. Autoindexing must have time to activate: the warmup count deliberately exceeds its initial observation threshold. Compiled plans, indexes and maintained group/prejoin structures may all contribute to warm results. Their cold build cost and write-maintenance cost are outside the latency table.&lt;br /&gt;
&lt;br /&gt;
Cold startup and initial automatic structure building are not represented by this table. Both MemCP modes reuse the same freshly imported, rebuilt directory sequentially; persisted structures and OS caches remain available. An earlier preparation pass populated some structures before the final measured run. This is deliberately a warm comparison, not a cold-start A/B test.&lt;br /&gt;
&lt;br /&gt;
=== Fixture ===&lt;br /&gt;
&lt;br /&gt;
The seven captured queries exercise option lookups, plugin metadata, taxonomy joins, comment counts, search and archives. The data is synthetic, with real WordPress query shapes. It is not a million-post or concurrent-production benchmark. The source WordPress installation identifies itself as 7.1; WordPress/PHP rendering does not execute in the SQL matrix, and installed plugin versions are not performance inputs once these exact queries are captured.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Contents !! Rows&lt;br /&gt;
|-&lt;br /&gt;
| wp_posts || Posts, pages, revisions and other post types || 22,063&lt;br /&gt;
|-&lt;br /&gt;
| wp_postmeta || Post metadata || 14,013&lt;br /&gt;
|-&lt;br /&gt;
| wp_comments || Comments || 6,001&lt;br /&gt;
|-&lt;br /&gt;
| wp_options || Site options || 503&lt;br /&gt;
|-&lt;br /&gt;
| wp_terms || Terms (category/tag names) || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_taxonomy || Term assignments to taxonomy types || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_relationships || Object-to-taxonomy relationships || 7,701&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The corpus contains 2,000 varied generated articles across 16 topics and 20,000 revisions. Titles, excerpts and bodies vary; body lengths range from 396 to 6,996 bytes (median 1,763). The search query uses realistic, present in 80 generated articles; the full query also considers other post types. Low-cardinality fields such as status and categories naturally repeat. This version-2 corpus must not be mixed with older version-1 measurements.&lt;br /&gt;
&lt;br /&gt;
== Try MemCP with your PHP hosting ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP is faster on the substantial repeated SQL work measured here. Try it with your own PHP hosting.&#039;&#039;&#039; Start with a copy of your site&#039;s data and replay its frequent queries: counts, searches, archives and plugin joins are useful starting points. Compare complete results and total counts, then measure full uncached HTTP requests and representative writes. You can retain the MySQL wire interface or explore direct PHP hosting to remove transport overhead from many small calls.&lt;br /&gt;
&lt;br /&gt;
WordPress is the example, not the product boundary. The same PHP-folder handler and PDO bridge can host other PHP applications; application and plugin compatibility still needs to be checked for the software you deploy.&lt;br /&gt;
&lt;br /&gt;
== Measurement artifacts and exact queries ==&lt;br /&gt;
&lt;br /&gt;
Local artifact directory: &amp;lt;code&amp;gt;../wordpress-db-lab/measurements/wiki-master-43d0c8140/&amp;lt;/code&amp;gt;. It contains results-master.json (raw batch means and complete query results), php-latency.json (all PHP samples), manifest.json, counts.json, corpus.json, text-parity.json, server logs, and a copied benchmark.py. The SQL runner can be repeated against the same fixture; its WP_BINARY and WP_WORKTREE overrides are for separately labelled candidate checks. Candidate measurements are not included in this master matrix.&lt;br /&gt;
&lt;br /&gt;
Source queries: &amp;lt;code&amp;gt;../wordpress-db-lab/profiles/queries/&amp;lt;/code&amp;gt;. They are reproduced below so that the benchmark shapes, including actual ORDER BY clauses, are unambiguous.&lt;br /&gt;
&lt;br /&gt;
=== Option lookup: siteurl ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Copyright (C) 2026 MemCP WordPress lab contributors&lt;br /&gt;
-- SPDX-License-Identifier: AGPL-3.0-or-later&lt;br /&gt;
SELECT option_value FROM wp_options WHERE option_name = &#039;siteurl&#039; LIMIT 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Elementor metadata join + LIMIT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_elementor_template_type&#039; AND wp_postmeta.meta_value = &#039;landing-page&#039; ) ) AND wp_posts.post_type = &#039;e-landing-page&#039; AND ((wp_posts.post_status &amp;lt;&amp;gt; &#039;trash&#039; AND wp_posts.post_status &amp;lt;&amp;gt; &#039;auto-draft&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Taxonomy DISTINCT/join, ordered by name ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT t.term_id, tr.object_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN (&#039;category&#039;, &#039;post_tag&#039;, &#039;post_format&#039;) AND tr.object_id IN (1, 21993, 21982, 21971, 21960) ORDER BY t.name ASC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Comment count with join ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM wp_comments LEFT JOIN wp_posts AS wp_posts_to_exclude_reviews ON comment_post_ID = wp_posts_to_exclude_reviews.ID WHERE ( comment_approved = &#039;1&#039; ) AND comment_type NOT IN (&#039;note&#039;) AND comment_type != &#039;order_note&#039; AND comment_type != &#039;webhook_delivery&#039; AND comment_type != &#039;action_log&#039; AND wp_posts_to_exclude_reviews.post_type NOT IN (&#039;product&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WordPress search + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND ( wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN (166) ) ) AND (((wp_posts.post_title LIKE &#039;%realistic%&#039;) OR (wp_posts.post_excerpt LIKE &#039;%realistic%&#039;) OR (wp_posts.post_content LIKE &#039;%realistic%&#039;))) AND ((wp_posts.post_type = &#039;attachment&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;e-floating-buttons&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;page&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;post&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;product&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;))) GROUP BY wp_posts.ID ORDER BY wp_posts.post_title LIKE &#039;%realistic%&#039; DESC, wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Yoast CAST metadata join + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_yoast_wpseo_linkdex&#039; AND CAST(wp_postmeta.meta_value AS SIGNED) BETWEEN &#039;1&#039; AND &#039;40&#039; ) ) AND wp_posts.post_type = &#039;post&#039; AND ((wp_posts.post_status = &#039;publish&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Monthly archive DISTINCT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM wp_posts WHERE post_type = &#039;post&#039; AND post_status != &#039;auto-draft&#039; AND post_status != &#039;trash&#039; ORDER BY post_date DESC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=417</id>
		<title>Benchmark MemCP vs. MariaDB on Wordpress</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=417"/>
		<updated>2026-09-09T21:43:07Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 MemCP contributors --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: AGPL-3.0-or-later --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP makes repeated WordPress database work faster.&#039;&#039;&#039; On current master, MemCP-JIT completes this fixture&#039;s search plus total-count query &#039;&#039;&#039;36.0× faster&#039;&#039;&#039; than MariaDB, its comment count &#039;&#039;&#039;21.1× faster&#039;&#039;&#039;, and its archive query &#039;&#039;&#039;6.2× faster&#039;&#039;&#039;. MemCP-JIT has lower measured warm latency across all seven query shapes in this run.&lt;br /&gt;
&lt;br /&gt;
MemCP speaks the MySQL protocol and can also &#039;&#039;&#039;host PHP directly in the database process&#039;&#039;&#039;. WordPress is our example application: the hosting interface is general purpose and is also intended for MediaWiki and other PHP software. Try MemCP with your PHP hosting and measure the queries your application actually runs.&lt;br /&gt;
&lt;br /&gt;
== MariaDB vs. MemCP vs. MemCP-JIT ==&lt;br /&gt;
&lt;br /&gt;
Measured on master [https://github.com/launix-de/memcp/commit/43d0c81401616fafeeb456b22f4a47d6e25361d6 43d0c8140], including the SQL literal-parameterization improvement in PR #873. All three columns use the same seven WordPress query shapes and data snapshot. These are &#039;&#039;&#039;warm database round trips&#039;&#039;&#039;, not HTTP page-load times. Lower is better.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dataset size:&#039;&#039;&#039; 22,063 rows in wp_posts (including 2,000 generated articles and 20,000 revisions), 14,013 post-metadata rows, 6,001 comments and 503 options. Taxonomy data comprises 175 terms, 175 term-taxonomy entries and 7,701 object-to-taxonomy relationships. These are the measured snapshot&#039;s table counts, not the number of rows returned by each query.&lt;br /&gt;
&lt;br /&gt;
Each value is the median of 11 batch means, each containing 100 complete query executions, after 30 warmups. For SQL_CALC_FOUND_ROWS statements, the measured operation also includes the subsequent SELECT FOUND_ROWS() on the same connection.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Query !! MariaDB (ms) !! MemCP (ms) !! MemCP-JIT (ms) !! MariaDB / JIT !! Result check&lt;br /&gt;
|-&lt;br /&gt;
| Option lookup: siteurl || 0.079 || 0.069 || &#039;&#039;&#039;0.056&#039;&#039;&#039; || 1.39× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| Elementor metadata join + LIMIT || 0.152 || 0.108 || &#039;&#039;&#039;0.079&#039;&#039;&#039; || 1.93× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Taxonomy DISTINCT/join, ordered by name || 0.224 || 0.245 || &#039;&#039;&#039;0.142&#039;&#039;&#039; || 1.58× || Equal&lt;br /&gt;
|-&lt;br /&gt;
| Comment count with join || 3.240 || 0.222 || &#039;&#039;&#039;0.153&#039;&#039;&#039; || 21.14× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| WordPress search + FOUND_ROWS || 30.405 || 1.278 || &#039;&#039;&#039;0.844&#039;&#039;&#039; || 36.01× || Equal; 10 rows&lt;br /&gt;
|-&lt;br /&gt;
| Yoast CAST metadata join + FOUND_ROWS || 0.197 || 0.248 || &#039;&#039;&#039;0.144&#039;&#039;&#039; || 1.37× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Monthly archive DISTINCT || 0.718 || 0.168 || &#039;&#039;&#039;0.116&#039;&#039;&#039; || 6.21× || Equal; 10 rows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Timing values are from master 43d0c8140. Taxonomy result equality (all 15 rows, including their order) was verified separately with [https://github.com/launix-de/memcp/pull/871 PR #871].&lt;br /&gt;
&lt;br /&gt;
The two metadata queries return zero rows on this snapshot. Their times describe proving an empty result, not retrieving a populated plugin workload. Tiny differences in the smallest queries are sensitive to scheduling on this shared development machine. We do not average these seven unrelated query shapes into a single WordPress speedup.&lt;br /&gt;
&lt;br /&gt;
== Host PHP directly: remove a round trip for every small query ==&lt;br /&gt;
&lt;br /&gt;
The optional FrankenPHP dependency supplies the PHP runtime; only MemCP&#039;s own bridge and PDO addon live in this repository. PHP requests use ZTS threads, with OPcache enabled. PHP folders are attached through the existing HTTP handler, alongside the SQL API and dashboard.&lt;br /&gt;
&lt;br /&gt;
With a PHP-enabled build and an external ZTS PHP development installation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
make php PHP_CONFIG=/path/to/zts/php-config&lt;br /&gt;
./memcp-php --no-repl -data /path/to/data --api-port=8098 --mysql-port=3307 --serve=/path/to/php-app lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The application is mounted at /; /dashboard remains available. Scheme code can mount additional applications through servePHP. No WordPress source is bundled into MemCP.&lt;br /&gt;
&lt;br /&gt;
The PDO addon supports authenticated memcp: connections and retains ordinary MySQL wire connections. A mysql: connection to localhost/127.0.0.1 and this MemCP server&#039;s own MySQL port can be routed internally; other destinations continue using their original driver. Both paths require database credentials. WordPress&#039;s use of mysqli is a separate connector question: PDO routing alone is not a claim that every WordPress installation or plugin uses PDO.&lt;br /&gt;
&lt;br /&gt;
A separate microbenchmark measures SELECT 1 inside PHP, using an already established connection. Each round performs 100 warmups and 2,000 measured executions; seven rounds alternate the two transports. The timer includes query(), fetchColumn(), and closeCursor(), but excludes HTTP, connection establishment, and PHP startup. Pdo\Mysql::connect forces the real wire driver for the control, so automatic PDO routing cannot accidentally turn both measurements into RAM calls.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! PHP SELECT 1 transport !! Median of round medians&lt;br /&gt;
|-&lt;br /&gt;
| MySQL wire over local TCP || 37.19 µs&lt;br /&gt;
|-&lt;br /&gt;
| MemCP in-process PDO || &#039;&#039;&#039;11.57 µs&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This removes &#039;&#039;&#039;69% of the measured latency&#039;&#039;&#039;, or 25.61 µs per tiny query. At 100 such queries per request, the arithmetic saving is approximately 2.56 ms; at 1,000 queries it is 25.61 ms. Those are extrapolations, not measured WordPress page-load improvements.&lt;br /&gt;
&lt;br /&gt;
For a workload-specific budgeting example, halving 100–200 µs of overhead would save &#039;&#039;&#039;50–100 µs per call (50%)&#039;&#039;&#039;. Across 100 database calls, that would add up to 5–10 ms per request. Those figures illustrate how small savings accumulate; they were not measured here. The measured transport comparison above is the evidence for this setup; measure your own query mix before assigning a per-request saving.&lt;br /&gt;
&lt;br /&gt;
== Reproducible setup ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Item !! Configuration&lt;br /&gt;
|-&lt;br /&gt;
| Measurement date || 9 September 2026 (Europe/Berlin)&lt;br /&gt;
|-&lt;br /&gt;
| CPU || AMD Ryzen 9 7900X3D, 12 physical cores / 24 logical CPUs&lt;br /&gt;
|-&lt;br /&gt;
| Memory / OS || Approximately 62 GiB RAM; Ubuntu 24.04.4 LTS, x86-64&lt;br /&gt;
|-&lt;br /&gt;
| MemCP || Master 43d0c81401616fafeeb456b22f4a47d6e25361d6; unchanged source for both SQL builds&lt;br /&gt;
|-&lt;br /&gt;
| SQL compiler/toolchain || Patched Go 1.27.0, revision 84fe25ee45468f5e3920c11c24e2bbb926fc3a72; GOEXPERIMENT empty vs. GOEXPERIMENT=jit&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB || 10.11.14; query cache OFF; InnoDB buffer pool 128 MiB&lt;br /&gt;
|-&lt;br /&gt;
| PHP microbenchmark || Same MemCP master, built with Go 1.26.0; PHP 8.5.10 ZTS, Zend Engine 4.5.10, OPcache enabled; FrankenPHP v1.12.7; no Go JIT&lt;br /&gt;
|-&lt;br /&gt;
| SQL client || Python 3.12 / PyMySQL, established TCP connections to 127.0.0.1; complete result fetching; no connection setup timed&lt;br /&gt;
|-&lt;br /&gt;
| Database fixture || Read-only consistent snapshot of wordpress_bench_v2, copied to a separate MemCP database; MariaDB InnoDB vs. MemCP sloppy engine; rebuild before measurements&lt;br /&gt;
|-&lt;br /&gt;
| Measurement order || MariaDB, MemCP, MemCP-JIT; one client, no concurrent query load&lt;br /&gt;
|-&lt;br /&gt;
| Runtime settings || Query-plan cache, autoindexing and normal optimizer enabled; TracePrint and ScanDebugging disabled while timing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This is a warm read comparison, not a matched-memory or durability benchmark. The host is shared with development services; cooperating builds/tests were paused for timing, but CPUs and memory were not reserved or pinned. Autoindexing must have time to activate: the warmup count deliberately exceeds its initial observation threshold. Compiled plans, indexes and maintained group/prejoin structures may all contribute to warm results. Their cold build cost and write-maintenance cost are outside the latency table.&lt;br /&gt;
&lt;br /&gt;
Cold startup and initial automatic structure building are not represented by this table. Both MemCP modes reuse the same freshly imported, rebuilt directory sequentially; persisted structures and OS caches remain available. An earlier preparation pass populated some structures before the final measured run. This is deliberately a warm comparison, not a cold-start A/B test.&lt;br /&gt;
&lt;br /&gt;
=== Fixture ===&lt;br /&gt;
&lt;br /&gt;
The seven captured queries exercise option lookups, plugin metadata, taxonomy joins, comment counts, search and archives. The data is synthetic, with real WordPress query shapes. It is not a million-post or concurrent-production benchmark. The source WordPress installation identifies itself as 7.1; WordPress/PHP rendering does not execute in the SQL matrix, and installed plugin versions are not performance inputs once these exact queries are captured.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Contents !! Rows&lt;br /&gt;
|-&lt;br /&gt;
| wp_posts || Posts, pages, revisions and other post types || 22,063&lt;br /&gt;
|-&lt;br /&gt;
| wp_postmeta || Post metadata || 14,013&lt;br /&gt;
|-&lt;br /&gt;
| wp_comments || Comments || 6,001&lt;br /&gt;
|-&lt;br /&gt;
| wp_options || Site options || 503&lt;br /&gt;
|-&lt;br /&gt;
| wp_terms || Terms (category/tag names) || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_taxonomy || Term assignments to taxonomy types || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_relationships || Object-to-taxonomy relationships || 7,701&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The corpus contains 2,000 varied generated articles across 16 topics and 20,000 revisions. Titles, excerpts and bodies vary; body lengths range from 396 to 6,996 bytes (median 1,763). The search query uses realistic, present in 80 generated articles; the full query also considers other post types. Low-cardinality fields such as status and categories naturally repeat. This version-2 corpus must not be mixed with older version-1 measurements.&lt;br /&gt;
&lt;br /&gt;
== Try MemCP with your PHP hosting ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP is faster on the substantial repeated SQL work measured here. Try it with your own PHP hosting.&#039;&#039;&#039; Start with a copy of your site&#039;s data and replay its frequent queries: counts, searches, archives and plugin joins are useful starting points. Compare complete results and total counts, then measure full uncached HTTP requests and representative writes. You can retain the MySQL wire interface or explore direct PHP hosting to remove transport overhead from many small calls.&lt;br /&gt;
&lt;br /&gt;
WordPress is the example, not the product boundary. The same PHP-folder handler and PDO bridge can host other PHP applications; application and plugin compatibility still needs to be checked for the software you deploy.&lt;br /&gt;
&lt;br /&gt;
== Measurement artifacts and exact queries ==&lt;br /&gt;
&lt;br /&gt;
Local artifact directory: &amp;lt;code&amp;gt;../wordpress-db-lab/measurements/wiki-master-43d0c8140/&amp;lt;/code&amp;gt;. It contains results-master.json (raw batch means and complete query results), php-latency.json (all PHP samples), manifest.json, counts.json, corpus.json, text-parity.json, server logs, and a copied benchmark.py. The SQL runner can be repeated against the same fixture; its WP_BINARY and WP_WORKTREE overrides are for separately labelled candidate checks. Candidate measurements are not included in this master matrix.&lt;br /&gt;
&lt;br /&gt;
Source queries: &amp;lt;code&amp;gt;../wordpress-db-lab/profiles/queries/&amp;lt;/code&amp;gt;. They are reproduced below so that the benchmark shapes, including actual ORDER BY clauses, are unambiguous.&lt;br /&gt;
&lt;br /&gt;
=== Option lookup: siteurl ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Copyright (C) 2026 MemCP WordPress lab contributors&lt;br /&gt;
-- SPDX-License-Identifier: AGPL-3.0-or-later&lt;br /&gt;
SELECT option_value FROM wp_options WHERE option_name = &#039;siteurl&#039; LIMIT 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Elementor metadata join + LIMIT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_elementor_template_type&#039; AND wp_postmeta.meta_value = &#039;landing-page&#039; ) ) AND wp_posts.post_type = &#039;e-landing-page&#039; AND ((wp_posts.post_status &amp;lt;&amp;gt; &#039;trash&#039; AND wp_posts.post_status &amp;lt;&amp;gt; &#039;auto-draft&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Taxonomy DISTINCT/join, ordered by name ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT t.term_id, tr.object_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN (&#039;category&#039;, &#039;post_tag&#039;, &#039;post_format&#039;) AND tr.object_id IN (1, 21993, 21982, 21971, 21960) ORDER BY t.name ASC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Comment count with join ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM wp_comments LEFT JOIN wp_posts AS wp_posts_to_exclude_reviews ON comment_post_ID = wp_posts_to_exclude_reviews.ID WHERE ( comment_approved = &#039;1&#039; ) AND comment_type NOT IN (&#039;note&#039;) AND comment_type != &#039;order_note&#039; AND comment_type != &#039;webhook_delivery&#039; AND comment_type != &#039;action_log&#039; AND wp_posts_to_exclude_reviews.post_type NOT IN (&#039;product&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WordPress search + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND ( wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN (166) ) ) AND (((wp_posts.post_title LIKE &#039;%realistic%&#039;) OR (wp_posts.post_excerpt LIKE &#039;%realistic%&#039;) OR (wp_posts.post_content LIKE &#039;%realistic%&#039;))) AND ((wp_posts.post_type = &#039;attachment&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;e-floating-buttons&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;page&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;post&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;product&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;))) GROUP BY wp_posts.ID ORDER BY wp_posts.post_title LIKE &#039;%realistic%&#039; DESC, wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Yoast CAST metadata join + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_yoast_wpseo_linkdex&#039; AND CAST(wp_postmeta.meta_value AS SIGNED) BETWEEN &#039;1&#039; AND &#039;40&#039; ) ) AND wp_posts.post_type = &#039;post&#039; AND ((wp_posts.post_status = &#039;publish&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Monthly archive DISTINCT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM wp_posts WHERE post_type = &#039;post&#039; AND post_status != &#039;auto-draft&#039; AND post_status != &#039;trash&#039; ORDER BY post_date DESC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=416</id>
		<title>Benchmark MemCP vs. MariaDB on Wordpress</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=416"/>
		<updated>2026-09-09T21:39:03Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 MemCP contributors --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: AGPL-3.0-or-later --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP makes repeated WordPress database work faster.&#039;&#039;&#039; On current master, MemCP-JIT completes this fixture&#039;s search plus total-count query &#039;&#039;&#039;36.0× faster&#039;&#039;&#039; than MariaDB, its comment count &#039;&#039;&#039;21.1× faster&#039;&#039;&#039;, and its archive query &#039;&#039;&#039;6.2× faster&#039;&#039;&#039;. MemCP-JIT has lower measured warm latency across all seven query shapes in this run.&lt;br /&gt;
&lt;br /&gt;
MemCP speaks the MySQL protocol and can also &#039;&#039;&#039;host PHP directly in the database process&#039;&#039;&#039;. WordPress is our example application: the hosting interface is general purpose and is also intended for MediaWiki and other PHP software. Try MemCP with your PHP hosting and measure the queries your application actually runs.&lt;br /&gt;
&lt;br /&gt;
== MariaDB vs. MemCP vs. MemCP-JIT ==&lt;br /&gt;
&lt;br /&gt;
Measured on master [https://github.com/launix-de/memcp/commit/43d0c81401616fafeeb456b22f4a47d6e25361d6 43d0c8140], including the SQL literal-parameterization improvement in PR #873. All three columns use the same seven WordPress query shapes and data snapshot. These are &#039;&#039;&#039;warm database round trips&#039;&#039;&#039;, not HTTP page-load times. Lower is better.&lt;br /&gt;
&lt;br /&gt;
Each value is the median of 11 batch means, each containing 100 complete query executions, after 30 warmups. For SQL_CALC_FOUND_ROWS statements, the measured operation also includes the subsequent SELECT FOUND_ROWS() on the same connection.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Query !! MariaDB (ms) !! MemCP (ms) !! MemCP-JIT (ms) !! MariaDB / JIT !! Result check&lt;br /&gt;
|-&lt;br /&gt;
| Option lookup: siteurl || 0.079 || 0.069 || &#039;&#039;&#039;0.056&#039;&#039;&#039; || 1.39× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| Elementor metadata join + LIMIT || 0.152 || 0.108 || &#039;&#039;&#039;0.079&#039;&#039;&#039; || 1.93× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Taxonomy DISTINCT/join, ordered by name || 0.224 || 0.245 || &#039;&#039;&#039;0.142&#039;&#039;&#039; || 1.58× || Equal&lt;br /&gt;
|-&lt;br /&gt;
| Comment count with join || 3.240 || 0.222 || &#039;&#039;&#039;0.153&#039;&#039;&#039; || 21.14× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| WordPress search + FOUND_ROWS || 30.405 || 1.278 || &#039;&#039;&#039;0.844&#039;&#039;&#039; || 36.01× || Equal; 10 rows&lt;br /&gt;
|-&lt;br /&gt;
| Yoast CAST metadata join + FOUND_ROWS || 0.197 || 0.248 || &#039;&#039;&#039;0.144&#039;&#039;&#039; || 1.37× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Monthly archive DISTINCT || 0.718 || 0.168 || &#039;&#039;&#039;0.116&#039;&#039;&#039; || 6.21× || Equal; 10 rows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Timing values are from master 43d0c8140. Taxonomy result equality (all 15 rows, including their order) was verified separately with [https://github.com/launix-de/memcp/pull/871 PR #871].&lt;br /&gt;
&lt;br /&gt;
The two metadata queries return zero rows on this snapshot. Their times describe proving an empty result, not retrieving a populated plugin workload. Tiny differences in the smallest queries are sensitive to scheduling on this shared development machine. We do not average these seven unrelated query shapes into a single WordPress speedup.&lt;br /&gt;
&lt;br /&gt;
== Host PHP directly: remove a round trip for every small query ==&lt;br /&gt;
&lt;br /&gt;
The optional FrankenPHP dependency supplies the PHP runtime; only MemCP&#039;s own bridge and PDO addon live in this repository. PHP requests use ZTS threads, with OPcache enabled. PHP folders are attached through the existing HTTP handler, alongside the SQL API and dashboard.&lt;br /&gt;
&lt;br /&gt;
With a PHP-enabled build and an external ZTS PHP development installation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
make php PHP_CONFIG=/path/to/zts/php-config&lt;br /&gt;
./memcp-php --no-repl -data /path/to/data --api-port=8098 --mysql-port=3307 --serve=/path/to/php-app lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The application is mounted at /; /dashboard remains available. Scheme code can mount additional applications through servePHP. No WordPress source is bundled into MemCP.&lt;br /&gt;
&lt;br /&gt;
The PDO addon supports authenticated memcp: connections and retains ordinary MySQL wire connections. A mysql: connection to localhost/127.0.0.1 and this MemCP server&#039;s own MySQL port can be routed internally; other destinations continue using their original driver. Both paths require database credentials. WordPress&#039;s use of mysqli is a separate connector question: PDO routing alone is not a claim that every WordPress installation or plugin uses PDO.&lt;br /&gt;
&lt;br /&gt;
A separate microbenchmark measures SELECT 1 inside PHP, using an already established connection. Each round performs 100 warmups and 2,000 measured executions; seven rounds alternate the two transports. The timer includes query(), fetchColumn(), and closeCursor(), but excludes HTTP, connection establishment, and PHP startup. Pdo\Mysql::connect forces the real wire driver for the control, so automatic PDO routing cannot accidentally turn both measurements into RAM calls.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! PHP SELECT 1 transport !! Median of round medians&lt;br /&gt;
|-&lt;br /&gt;
| MySQL wire over local TCP || 37.19 µs&lt;br /&gt;
|-&lt;br /&gt;
| MemCP in-process PDO || &#039;&#039;&#039;11.57 µs&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This removes &#039;&#039;&#039;69% of the measured latency&#039;&#039;&#039;, or 25.61 µs per tiny query. At 100 such queries per request, the arithmetic saving is approximately 2.56 ms; at 1,000 queries it is 25.61 ms. Those are extrapolations, not measured WordPress page-load improvements.&lt;br /&gt;
&lt;br /&gt;
For a workload-specific budgeting example, halving 100–200 µs of overhead would save &#039;&#039;&#039;50–100 µs per call (50%)&#039;&#039;&#039;. Across 100 database calls, that would add up to 5–10 ms per request. Those figures illustrate how small savings accumulate; they were not measured here. The measured transport comparison above is the evidence for this setup; measure your own query mix before assigning a per-request saving.&lt;br /&gt;
&lt;br /&gt;
== Reproducible setup ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Item !! Configuration&lt;br /&gt;
|-&lt;br /&gt;
| Measurement date || 9 September 2026 (Europe/Berlin)&lt;br /&gt;
|-&lt;br /&gt;
| CPU || AMD Ryzen 9 7900X3D, 12 physical cores / 24 logical CPUs&lt;br /&gt;
|-&lt;br /&gt;
| Memory / OS || Approximately 62 GiB RAM; Ubuntu 24.04.4 LTS, x86-64&lt;br /&gt;
|-&lt;br /&gt;
| MemCP || Master 43d0c81401616fafeeb456b22f4a47d6e25361d6; unchanged source for both SQL builds&lt;br /&gt;
|-&lt;br /&gt;
| SQL compiler/toolchain || Patched Go 1.27.0, revision 84fe25ee45468f5e3920c11c24e2bbb926fc3a72; GOEXPERIMENT empty vs. GOEXPERIMENT=jit&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB || 10.11.14; query cache OFF; InnoDB buffer pool 128 MiB&lt;br /&gt;
|-&lt;br /&gt;
| PHP microbenchmark || Same MemCP master, built with Go 1.26.0; PHP 8.5.10 ZTS, Zend Engine 4.5.10, OPcache enabled; FrankenPHP v1.12.7; no Go JIT&lt;br /&gt;
|-&lt;br /&gt;
| SQL client || Python 3.12 / PyMySQL, established TCP connections to 127.0.0.1; complete result fetching; no connection setup timed&lt;br /&gt;
|-&lt;br /&gt;
| Database fixture || Read-only consistent snapshot of wordpress_bench_v2, copied to a separate MemCP database; MariaDB InnoDB vs. MemCP sloppy engine; rebuild before measurements&lt;br /&gt;
|-&lt;br /&gt;
| Measurement order || MariaDB, MemCP, MemCP-JIT; one client, no concurrent query load&lt;br /&gt;
|-&lt;br /&gt;
| Runtime settings || Query-plan cache, autoindexing and normal optimizer enabled; TracePrint and ScanDebugging disabled while timing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This is a warm read comparison, not a matched-memory or durability benchmark. The host is shared with development services; cooperating builds/tests were paused for timing, but CPUs and memory were not reserved or pinned. Autoindexing must have time to activate: the warmup count deliberately exceeds its initial observation threshold. Compiled plans, indexes and maintained group/prejoin structures may all contribute to warm results. Their cold build cost and write-maintenance cost are outside the latency table.&lt;br /&gt;
&lt;br /&gt;
Cold startup and initial automatic structure building are not represented by this table. Both MemCP modes reuse the same freshly imported, rebuilt directory sequentially; persisted structures and OS caches remain available. An earlier preparation pass populated some structures before the final measured run. This is deliberately a warm comparison, not a cold-start A/B test.&lt;br /&gt;
&lt;br /&gt;
=== Fixture ===&lt;br /&gt;
&lt;br /&gt;
The seven captured queries exercise option lookups, plugin metadata, taxonomy joins, comment counts, search and archives. The data is synthetic, with real WordPress query shapes. It is not a million-post or concurrent-production benchmark. The source WordPress installation identifies itself as 7.1; WordPress/PHP rendering does not execute in the SQL matrix, and installed plugin versions are not performance inputs once these exact queries are captured.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Rows&lt;br /&gt;
|-&lt;br /&gt;
| wp_posts || 22,063&lt;br /&gt;
|-&lt;br /&gt;
| wp_postmeta || 14,013&lt;br /&gt;
|-&lt;br /&gt;
| wp_comments || 6,001&lt;br /&gt;
|-&lt;br /&gt;
| wp_options || 503&lt;br /&gt;
|-&lt;br /&gt;
| wp_terms || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_taxonomy || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_relationships || 7,701&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The corpus contains 2,000 varied generated articles across 16 topics and 20,000 revisions. Titles, excerpts and bodies vary; body lengths range from 396 to 6,996 bytes (median 1,763). The search query uses realistic, present in 80 generated articles; the full query also considers other post types. Low-cardinality fields such as status and categories naturally repeat. This version-2 corpus must not be mixed with older version-1 measurements.&lt;br /&gt;
&lt;br /&gt;
== Try MemCP with your PHP hosting ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP is faster on the substantial repeated SQL work measured here. Try it with your own PHP hosting.&#039;&#039;&#039; Start with a copy of your site&#039;s data and replay its frequent queries: counts, searches, archives and plugin joins are useful starting points. Compare complete results and total counts, then measure full uncached HTTP requests and representative writes. You can retain the MySQL wire interface or explore direct PHP hosting to remove transport overhead from many small calls.&lt;br /&gt;
&lt;br /&gt;
WordPress is the example, not the product boundary. The same PHP-folder handler and PDO bridge can host other PHP applications; application and plugin compatibility still needs to be checked for the software you deploy.&lt;br /&gt;
&lt;br /&gt;
== Measurement artifacts and exact queries ==&lt;br /&gt;
&lt;br /&gt;
Local artifact directory: &amp;lt;code&amp;gt;../wordpress-db-lab/measurements/wiki-master-43d0c8140/&amp;lt;/code&amp;gt;. It contains results-master.json (raw batch means and complete query results), php-latency.json (all PHP samples), manifest.json, counts.json, corpus.json, text-parity.json, server logs, and a copied benchmark.py. The SQL runner can be repeated against the same fixture; its WP_BINARY and WP_WORKTREE overrides are for separately labelled candidate checks. Candidate measurements are not included in this master matrix.&lt;br /&gt;
&lt;br /&gt;
Source queries: &amp;lt;code&amp;gt;../wordpress-db-lab/profiles/queries/&amp;lt;/code&amp;gt;. They are reproduced below so that the benchmark shapes, including actual ORDER BY clauses, are unambiguous.&lt;br /&gt;
&lt;br /&gt;
=== Option lookup: siteurl ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Copyright (C) 2026 MemCP WordPress lab contributors&lt;br /&gt;
-- SPDX-License-Identifier: AGPL-3.0-or-later&lt;br /&gt;
SELECT option_value FROM wp_options WHERE option_name = &#039;siteurl&#039; LIMIT 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Elementor metadata join + LIMIT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_elementor_template_type&#039; AND wp_postmeta.meta_value = &#039;landing-page&#039; ) ) AND wp_posts.post_type = &#039;e-landing-page&#039; AND ((wp_posts.post_status &amp;lt;&amp;gt; &#039;trash&#039; AND wp_posts.post_status &amp;lt;&amp;gt; &#039;auto-draft&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Taxonomy DISTINCT/join, ordered by name ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT t.term_id, tr.object_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN (&#039;category&#039;, &#039;post_tag&#039;, &#039;post_format&#039;) AND tr.object_id IN (1, 21993, 21982, 21971, 21960) ORDER BY t.name ASC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Comment count with join ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM wp_comments LEFT JOIN wp_posts AS wp_posts_to_exclude_reviews ON comment_post_ID = wp_posts_to_exclude_reviews.ID WHERE ( comment_approved = &#039;1&#039; ) AND comment_type NOT IN (&#039;note&#039;) AND comment_type != &#039;order_note&#039; AND comment_type != &#039;webhook_delivery&#039; AND comment_type != &#039;action_log&#039; AND wp_posts_to_exclude_reviews.post_type NOT IN (&#039;product&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WordPress search + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND ( wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN (166) ) ) AND (((wp_posts.post_title LIKE &#039;%realistic%&#039;) OR (wp_posts.post_excerpt LIKE &#039;%realistic%&#039;) OR (wp_posts.post_content LIKE &#039;%realistic%&#039;))) AND ((wp_posts.post_type = &#039;attachment&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;e-floating-buttons&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;page&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;post&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;product&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;))) GROUP BY wp_posts.ID ORDER BY wp_posts.post_title LIKE &#039;%realistic%&#039; DESC, wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Yoast CAST metadata join + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_yoast_wpseo_linkdex&#039; AND CAST(wp_postmeta.meta_value AS SIGNED) BETWEEN &#039;1&#039; AND &#039;40&#039; ) ) AND wp_posts.post_type = &#039;post&#039; AND ((wp_posts.post_status = &#039;publish&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Monthly archive DISTINCT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM wp_posts WHERE post_type = &#039;post&#039; AND post_status != &#039;auto-draft&#039; AND post_status != &#039;trash&#039; ORDER BY post_date DESC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=415</id>
		<title>Benchmark MemCP vs. MariaDB on Wordpress</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=415"/>
		<updated>2026-09-09T21:36:55Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 MemCP contributors --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: AGPL-3.0-or-later --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP makes repeated WordPress database work faster.&#039;&#039;&#039; On current master, MemCP-JIT completes this fixture&#039;s search plus total-count query &#039;&#039;&#039;36.0× faster&#039;&#039;&#039; than MariaDB, its comment count &#039;&#039;&#039;21.1× faster&#039;&#039;&#039;, and its archive query &#039;&#039;&#039;6.2× faster&#039;&#039;&#039;. MemCP-JIT has lower measured warm latency across all seven query shapes in this run.&lt;br /&gt;
&lt;br /&gt;
MemCP speaks the MySQL protocol and can also &#039;&#039;&#039;host PHP directly in the database process&#039;&#039;&#039;. WordPress is our example application: the hosting interface is general purpose and is also intended for MediaWiki and other PHP software. Try MemCP with your PHP hosting and measure the queries your application actually runs.&lt;br /&gt;
&lt;br /&gt;
== MariaDB vs. MemCP vs. MemCP-JIT ==&lt;br /&gt;
&lt;br /&gt;
Measured on master [https://github.com/launix-de/memcp/commit/43d0c81401616fafeeb456b22f4a47d6e25361d6 43d0c8140], including the SQL literal-parameterization improvement in PR #873. All three columns use the same seven WordPress query shapes and data snapshot. These are &#039;&#039;&#039;warm database round trips&#039;&#039;&#039;, not HTTP page-load times. Lower is better.&lt;br /&gt;
&lt;br /&gt;
Each value is the median of 11 batch means, each containing 100 complete query executions, after 30 warmups. For SQL_CALC_FOUND_ROWS statements, the measured operation also includes the subsequent SELECT FOUND_ROWS() on the same connection.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Query !! MariaDB (ms) !! MemCP (ms) !! MemCP-JIT (ms) !! MariaDB / JIT !! Result check&lt;br /&gt;
|-&lt;br /&gt;
| Option lookup: siteurl || 0.079 || 0.069 || &#039;&#039;&#039;0.056&#039;&#039;&#039; || 1.39× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| Elementor metadata join + LIMIT || 0.152 || 0.108 || &#039;&#039;&#039;0.079&#039;&#039;&#039; || 1.93× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Taxonomy DISTINCT/join, ordered by name || 0.224 || 0.245 || &#039;&#039;&#039;0.142&#039;&#039;&#039; || Master timing || Fix: [https://github.com/launix-de/memcp/pull/871 PR #871] (in CI)&lt;br /&gt;
|-&lt;br /&gt;
| Comment count with join || 3.240 || 0.222 || &#039;&#039;&#039;0.153&#039;&#039;&#039; || 21.14× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| WordPress search + FOUND_ROWS || 30.405 || 1.278 || &#039;&#039;&#039;0.844&#039;&#039;&#039; || 36.01× || Equal; 10 rows&lt;br /&gt;
|-&lt;br /&gt;
| Yoast CAST metadata join + FOUND_ROWS || 0.197 || 0.248 || &#039;&#039;&#039;0.144&#039;&#039;&#039; || 1.37× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Monthly archive DISTINCT || 0.718 || 0.168 || &#039;&#039;&#039;0.116&#039;&#039;&#039; || 6.21× || Equal; 10 rows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two metadata queries return zero rows on this snapshot. Their times describe proving an empty result, not retrieving a populated plugin workload. Tiny differences in the smallest queries are sensitive to scheduling on this shared development machine. We do not average these seven unrelated query shapes into a single WordPress speedup.&lt;br /&gt;
&lt;br /&gt;
== Host PHP directly: remove a round trip for every small query ==&lt;br /&gt;
&lt;br /&gt;
The optional FrankenPHP dependency supplies the PHP runtime; only MemCP&#039;s own bridge and PDO addon live in this repository. PHP requests use ZTS threads, with OPcache enabled. PHP folders are attached through the existing HTTP handler, alongside the SQL API and dashboard.&lt;br /&gt;
&lt;br /&gt;
With a PHP-enabled build and an external ZTS PHP development installation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
make php PHP_CONFIG=/path/to/zts/php-config&lt;br /&gt;
./memcp-php --no-repl -data /path/to/data --api-port=8098 --mysql-port=3307 --serve=/path/to/php-app lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The application is mounted at /; /dashboard remains available. Scheme code can mount additional applications through servePHP. No WordPress source is bundled into MemCP.&lt;br /&gt;
&lt;br /&gt;
The PDO addon supports authenticated memcp: connections and retains ordinary MySQL wire connections. A mysql: connection to localhost/127.0.0.1 and this MemCP server&#039;s own MySQL port can be routed internally; other destinations continue using their original driver. Both paths require database credentials. WordPress&#039;s use of mysqli is a separate connector question: PDO routing alone is not a claim that every WordPress installation or plugin uses PDO.&lt;br /&gt;
&lt;br /&gt;
A separate microbenchmark measures SELECT 1 inside PHP, using an already established connection. Each round performs 100 warmups and 2,000 measured executions; seven rounds alternate the two transports. The timer includes query(), fetchColumn(), and closeCursor(), but excludes HTTP, connection establishment, and PHP startup. Pdo\Mysql::connect forces the real wire driver for the control, so automatic PDO routing cannot accidentally turn both measurements into RAM calls.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! PHP SELECT 1 transport !! Median of round medians&lt;br /&gt;
|-&lt;br /&gt;
| MySQL wire over local TCP || 37.19 µs&lt;br /&gt;
|-&lt;br /&gt;
| MemCP in-process PDO || &#039;&#039;&#039;11.57 µs&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This removes &#039;&#039;&#039;69% of the measured latency&#039;&#039;&#039;, or 25.61 µs per tiny query. At 100 such queries per request, the arithmetic saving is approximately 2.56 ms; at 1,000 queries it is 25.61 ms. Those are extrapolations, not measured WordPress page-load improvements.&lt;br /&gt;
&lt;br /&gt;
For a workload-specific budgeting example, halving 100–200 µs of overhead would save &#039;&#039;&#039;50–100 µs per call (50%)&#039;&#039;&#039;. Across 100 database calls, that would add up to 5–10 ms per request. Those figures illustrate how small savings accumulate; they were not measured here. The measured transport comparison above is the evidence for this setup; measure your own query mix before assigning a per-request saving.&lt;br /&gt;
&lt;br /&gt;
== Reproducible setup ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Item !! Configuration&lt;br /&gt;
|-&lt;br /&gt;
| Measurement date || 9 September 2026 (Europe/Berlin)&lt;br /&gt;
|-&lt;br /&gt;
| CPU || AMD Ryzen 9 7900X3D, 12 physical cores / 24 logical CPUs&lt;br /&gt;
|-&lt;br /&gt;
| Memory / OS || Approximately 62 GiB RAM; Ubuntu 24.04.4 LTS, x86-64&lt;br /&gt;
|-&lt;br /&gt;
| MemCP || Master 43d0c81401616fafeeb456b22f4a47d6e25361d6; unchanged source for both SQL builds&lt;br /&gt;
|-&lt;br /&gt;
| SQL compiler/toolchain || Patched Go 1.27.0, revision 84fe25ee45468f5e3920c11c24e2bbb926fc3a72; GOEXPERIMENT empty vs. GOEXPERIMENT=jit&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB || 10.11.14; query cache OFF; InnoDB buffer pool 128 MiB&lt;br /&gt;
|-&lt;br /&gt;
| PHP microbenchmark || Same MemCP master, built with Go 1.26.0; PHP 8.5.10 ZTS, Zend Engine 4.5.10, OPcache enabled; FrankenPHP v1.12.7; no Go JIT&lt;br /&gt;
|-&lt;br /&gt;
| SQL client || Python 3.12 / PyMySQL, established TCP connections to 127.0.0.1; complete result fetching; no connection setup timed&lt;br /&gt;
|-&lt;br /&gt;
| Database fixture || Read-only consistent snapshot of wordpress_bench_v2, copied to a separate MemCP database; MariaDB InnoDB vs. MemCP sloppy engine; rebuild before measurements&lt;br /&gt;
|-&lt;br /&gt;
| Measurement order || MariaDB, MemCP, MemCP-JIT; one client, no concurrent query load&lt;br /&gt;
|-&lt;br /&gt;
| Runtime settings || Query-plan cache, autoindexing and normal optimizer enabled; TracePrint and ScanDebugging disabled while timing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This is a warm read comparison, not a matched-memory or durability benchmark. The host is shared with development services; cooperating builds/tests were paused for timing, but CPUs and memory were not reserved or pinned. Autoindexing must have time to activate: the warmup count deliberately exceeds its initial observation threshold. Compiled plans, indexes and maintained group/prejoin structures may all contribute to warm results. Their cold build cost and write-maintenance cost are outside the latency table.&lt;br /&gt;
&lt;br /&gt;
Cold startup and initial automatic structure building are not represented by this table. Both MemCP modes reuse the same freshly imported, rebuilt directory sequentially; persisted structures and OS caches remain available. An earlier preparation pass populated some structures before the final measured run. This is deliberately a warm comparison, not a cold-start A/B test.&lt;br /&gt;
&lt;br /&gt;
=== Fixture ===&lt;br /&gt;
&lt;br /&gt;
The seven captured queries exercise option lookups, plugin metadata, taxonomy joins, comment counts, search and archives. The data is synthetic, with real WordPress query shapes. It is not a million-post or concurrent-production benchmark. The source WordPress installation identifies itself as 7.1; WordPress/PHP rendering does not execute in the SQL matrix, and installed plugin versions are not performance inputs once these exact queries are captured.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Rows&lt;br /&gt;
|-&lt;br /&gt;
| wp_posts || 22,063&lt;br /&gt;
|-&lt;br /&gt;
| wp_postmeta || 14,013&lt;br /&gt;
|-&lt;br /&gt;
| wp_comments || 6,001&lt;br /&gt;
|-&lt;br /&gt;
| wp_options || 503&lt;br /&gt;
|-&lt;br /&gt;
| wp_terms || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_taxonomy || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_relationships || 7,701&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The corpus contains 2,000 varied generated articles across 16 topics and 20,000 revisions. Titles, excerpts and bodies vary; body lengths range from 396 to 6,996 bytes (median 1,763). The search query uses realistic, present in 80 generated articles; the full query also considers other post types. Low-cardinality fields such as status and categories naturally repeat. This version-2 corpus must not be mixed with older version-1 measurements.&lt;br /&gt;
&lt;br /&gt;
== Try MemCP with your PHP hosting ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP is faster on the substantial repeated SQL work measured here. Try it with your own PHP hosting.&#039;&#039;&#039; Start with a copy of your site&#039;s data and replay its frequent queries: counts, searches, archives and plugin joins are useful starting points. Compare complete results and total counts, then measure full uncached HTTP requests and representative writes. You can retain the MySQL wire interface or explore direct PHP hosting to remove transport overhead from many small calls.&lt;br /&gt;
&lt;br /&gt;
WordPress is the example, not the product boundary. The same PHP-folder handler and PDO bridge can host other PHP applications; application and plugin compatibility still needs to be checked for the software you deploy.&lt;br /&gt;
&lt;br /&gt;
== Measurement artifacts and exact queries ==&lt;br /&gt;
&lt;br /&gt;
Local artifact directory: &amp;lt;code&amp;gt;../wordpress-db-lab/measurements/wiki-master-43d0c8140/&amp;lt;/code&amp;gt;. It contains results-master.json (raw batch means and complete query results), php-latency.json (all PHP samples), manifest.json, counts.json, corpus.json, text-parity.json, server logs, and a copied benchmark.py. The SQL runner can be repeated against the same fixture; its WP_BINARY and WP_WORKTREE overrides are for separately labelled candidate checks. Candidate measurements are not included in this master matrix.&lt;br /&gt;
&lt;br /&gt;
Source queries: &amp;lt;code&amp;gt;../wordpress-db-lab/profiles/queries/&amp;lt;/code&amp;gt;. They are reproduced below so that the benchmark shapes, including actual ORDER BY clauses, are unambiguous.&lt;br /&gt;
&lt;br /&gt;
=== Option lookup: siteurl ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Copyright (C) 2026 MemCP WordPress lab contributors&lt;br /&gt;
-- SPDX-License-Identifier: AGPL-3.0-or-later&lt;br /&gt;
SELECT option_value FROM wp_options WHERE option_name = &#039;siteurl&#039; LIMIT 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Elementor metadata join + LIMIT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_elementor_template_type&#039; AND wp_postmeta.meta_value = &#039;landing-page&#039; ) ) AND wp_posts.post_type = &#039;e-landing-page&#039; AND ((wp_posts.post_status &amp;lt;&amp;gt; &#039;trash&#039; AND wp_posts.post_status &amp;lt;&amp;gt; &#039;auto-draft&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Taxonomy DISTINCT/join, ordered by name ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT t.term_id, tr.object_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN (&#039;category&#039;, &#039;post_tag&#039;, &#039;post_format&#039;) AND tr.object_id IN (1, 21993, 21982, 21971, 21960) ORDER BY t.name ASC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Comment count with join ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM wp_comments LEFT JOIN wp_posts AS wp_posts_to_exclude_reviews ON comment_post_ID = wp_posts_to_exclude_reviews.ID WHERE ( comment_approved = &#039;1&#039; ) AND comment_type NOT IN (&#039;note&#039;) AND comment_type != &#039;order_note&#039; AND comment_type != &#039;webhook_delivery&#039; AND comment_type != &#039;action_log&#039; AND wp_posts_to_exclude_reviews.post_type NOT IN (&#039;product&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WordPress search + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND ( wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN (166) ) ) AND (((wp_posts.post_title LIKE &#039;%realistic%&#039;) OR (wp_posts.post_excerpt LIKE &#039;%realistic%&#039;) OR (wp_posts.post_content LIKE &#039;%realistic%&#039;))) AND ((wp_posts.post_type = &#039;attachment&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;e-floating-buttons&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;page&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;post&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;product&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;))) GROUP BY wp_posts.ID ORDER BY wp_posts.post_title LIKE &#039;%realistic%&#039; DESC, wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Yoast CAST metadata join + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_yoast_wpseo_linkdex&#039; AND CAST(wp_postmeta.meta_value AS SIGNED) BETWEEN &#039;1&#039; AND &#039;40&#039; ) ) AND wp_posts.post_type = &#039;post&#039; AND ((wp_posts.post_status = &#039;publish&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Monthly archive DISTINCT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM wp_posts WHERE post_type = &#039;post&#039; AND post_status != &#039;auto-draft&#039; AND post_status != &#039;trash&#039; ORDER BY post_date DESC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=414</id>
		<title>Benchmark MemCP vs. MariaDB on Wordpress</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=414"/>
		<updated>2026-09-09T21:36:38Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 MemCP contributors --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: AGPL-3.0-or-later --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Benchmark MemCP vs. MariaDB on Wordpress =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP makes repeated WordPress database work faster.&#039;&#039;&#039; On current master, MemCP-JIT completes this fixture&#039;s search plus total-count query &#039;&#039;&#039;36.0× faster&#039;&#039;&#039; than MariaDB, its comment count &#039;&#039;&#039;21.1× faster&#039;&#039;&#039;, and its archive query &#039;&#039;&#039;6.2× faster&#039;&#039;&#039;. All six query shapes with matching results have lower warm latency with JIT in this run. The seventh, a taxonomy query, is retained in the matrix with a clearly marked collation mismatch.&lt;br /&gt;
&lt;br /&gt;
MemCP speaks the MySQL protocol and can also &#039;&#039;&#039;host PHP directly in the database process&#039;&#039;&#039;. WordPress is our example application: the hosting interface is general purpose and is also intended for MediaWiki and other PHP software. Try MemCP with your PHP hosting and measure the queries your application actually runs.&lt;br /&gt;
&lt;br /&gt;
== MariaDB vs. MemCP vs. MemCP-JIT ==&lt;br /&gt;
&lt;br /&gt;
Measured on master [https://github.com/launix-de/memcp/commit/43d0c81401616fafeeb456b22f4a47d6e25361d6 43d0c8140], including the SQL literal-parameterization improvement in PR #873. All three columns use the same seven WordPress query shapes and data snapshot. These are &#039;&#039;&#039;warm database round trips&#039;&#039;&#039;, not HTTP page-load times. Lower is better.&lt;br /&gt;
&lt;br /&gt;
Each value is the median of 11 batch means, each containing 100 complete query executions, after 30 warmups. For SQL_CALC_FOUND_ROWS statements, the measured operation also includes the subsequent SELECT FOUND_ROWS() on the same connection.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Query !! MariaDB (ms) !! MemCP (ms) !! MemCP-JIT (ms) !! MariaDB / JIT !! Result check&lt;br /&gt;
|-&lt;br /&gt;
| Option lookup: siteurl || 0.079 || 0.069 || &#039;&#039;&#039;0.056&#039;&#039;&#039; || 1.39× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| Elementor metadata join + LIMIT || 0.152 || 0.108 || &#039;&#039;&#039;0.079&#039;&#039;&#039; || 1.93× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Taxonomy DISTINCT/join, ordered by name || 0.224 || 0.245 || &#039;&#039;&#039;0.142&#039;&#039;&#039; || Diagnostic only || See correctness notes below&lt;br /&gt;
|-&lt;br /&gt;
| Comment count with join || 3.240 || 0.222 || &#039;&#039;&#039;0.153&#039;&#039;&#039; || 21.14× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| WordPress search + FOUND_ROWS || 30.405 || 1.278 || &#039;&#039;&#039;0.844&#039;&#039;&#039; || 36.01× || Equal; 10 rows&lt;br /&gt;
|-&lt;br /&gt;
| Yoast CAST metadata join + FOUND_ROWS || 0.197 || 0.248 || &#039;&#039;&#039;0.144&#039;&#039;&#039; || 1.37× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Monthly archive DISTINCT || 0.718 || 0.168 || &#039;&#039;&#039;0.116&#039;&#039;&#039; || 6.21× || Equal; 10 rows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two metadata queries return zero rows on this snapshot. Their times describe proving an empty result, not retrieving a populated plugin workload. Tiny differences in the smallest queries are sensitive to scheduling on this shared development machine. We do not average these seven unrelated query shapes into a single WordPress speedup.&lt;br /&gt;
&lt;br /&gt;
== Host PHP directly: remove a round trip for every small query ==&lt;br /&gt;
&lt;br /&gt;
The optional FrankenPHP dependency supplies the PHP runtime; only MemCP&#039;s own bridge and PDO addon live in this repository. PHP requests use ZTS threads, with OPcache enabled. PHP folders are attached through the existing HTTP handler, alongside the SQL API and dashboard.&lt;br /&gt;
&lt;br /&gt;
With a PHP-enabled build and an external ZTS PHP development installation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
make php PHP_CONFIG=/path/to/zts/php-config&lt;br /&gt;
./memcp-php --no-repl -data /path/to/data --api-port=8098 --mysql-port=3307 --serve=/path/to/php-app lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The application is mounted at /; /dashboard remains available. Scheme code can mount additional applications through servePHP. No WordPress source is bundled into MemCP.&lt;br /&gt;
&lt;br /&gt;
The PDO addon supports authenticated memcp: connections and retains ordinary MySQL wire connections. A mysql: connection to localhost/127.0.0.1 and this MemCP server&#039;s own MySQL port can be routed internally; other destinations continue using their original driver. Both paths require database credentials. WordPress&#039;s use of mysqli is a separate connector question: PDO routing alone is not a claim that every WordPress installation or plugin uses PDO.&lt;br /&gt;
&lt;br /&gt;
A separate microbenchmark measures SELECT 1 inside PHP, using an already established connection. Each round performs 100 warmups and 2,000 measured executions; seven rounds alternate the two transports. The timer includes query(), fetchColumn(), and closeCursor(), but excludes HTTP, connection establishment, and PHP startup. Pdo\Mysql::connect forces the real wire driver for the control, so automatic PDO routing cannot accidentally turn both measurements into RAM calls.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! PHP SELECT 1 transport !! Median of round medians&lt;br /&gt;
|-&lt;br /&gt;
| MySQL wire over local TCP || 37.19 µs&lt;br /&gt;
|-&lt;br /&gt;
| MemCP in-process PDO || &#039;&#039;&#039;11.57 µs&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This removes &#039;&#039;&#039;69% of the measured latency&#039;&#039;&#039;, or 25.61 µs per tiny query. At 100 such queries per request, the arithmetic saving is approximately 2.56 ms; at 1,000 queries it is 25.61 ms. Those are extrapolations, not measured WordPress page-load improvements.&lt;br /&gt;
&lt;br /&gt;
For a workload-specific budgeting example, halving 100–200 µs of overhead would save &#039;&#039;&#039;50–100 µs per call (50%)&#039;&#039;&#039;. Across 100 database calls, that would add up to 5–10 ms per request. Those figures illustrate how small savings accumulate; they were not measured here. The measured transport comparison above is the evidence for this setup; measure your own query mix before assigning a per-request saving.&lt;br /&gt;
&lt;br /&gt;
== Reproducible setup ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Item !! Configuration&lt;br /&gt;
|-&lt;br /&gt;
| Measurement date || 9 September 2026 (Europe/Berlin)&lt;br /&gt;
|-&lt;br /&gt;
| CPU || AMD Ryzen 9 7900X3D, 12 physical cores / 24 logical CPUs&lt;br /&gt;
|-&lt;br /&gt;
| Memory / OS || Approximately 62 GiB RAM; Ubuntu 24.04.4 LTS, x86-64&lt;br /&gt;
|-&lt;br /&gt;
| MemCP || Master 43d0c81401616fafeeb456b22f4a47d6e25361d6; unchanged source for both SQL builds&lt;br /&gt;
|-&lt;br /&gt;
| SQL compiler/toolchain || Patched Go 1.27.0, revision 84fe25ee45468f5e3920c11c24e2bbb926fc3a72; GOEXPERIMENT empty vs. GOEXPERIMENT=jit&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB || 10.11.14; query cache OFF; InnoDB buffer pool 128 MiB&lt;br /&gt;
|-&lt;br /&gt;
| PHP microbenchmark || Same MemCP master, built with Go 1.26.0; PHP 8.5.10 ZTS, Zend Engine 4.5.10, OPcache enabled; FrankenPHP v1.12.7; no Go JIT&lt;br /&gt;
|-&lt;br /&gt;
| SQL client || Python 3.12 / PyMySQL, established TCP connections to 127.0.0.1; complete result fetching; no connection setup timed&lt;br /&gt;
|-&lt;br /&gt;
| Database fixture || Read-only consistent snapshot of wordpress_bench_v2, copied to a separate MemCP database; MariaDB InnoDB vs. MemCP sloppy engine; rebuild before measurements&lt;br /&gt;
|-&lt;br /&gt;
| Measurement order || MariaDB, MemCP, MemCP-JIT; one client, no concurrent query load&lt;br /&gt;
|-&lt;br /&gt;
| Runtime settings || Query-plan cache, autoindexing and normal optimizer enabled; TracePrint and ScanDebugging disabled while timing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This is a warm read comparison, not a matched-memory or durability benchmark. The host is shared with development services; cooperating builds/tests were paused for timing, but CPUs and memory were not reserved or pinned. Autoindexing must have time to activate: the warmup count deliberately exceeds its initial observation threshold. Compiled plans, indexes and maintained group/prejoin structures may all contribute to warm results. Their cold build cost and write-maintenance cost are outside the latency table.&lt;br /&gt;
&lt;br /&gt;
Cold startup and initial automatic structure building are not represented by this table. Both MemCP modes reuse the same freshly imported, rebuilt directory sequentially; persisted structures and OS caches remain available. An earlier preparation pass populated some structures before the final measured run. This is deliberately a warm comparison, not a cold-start A/B test.&lt;br /&gt;
&lt;br /&gt;
=== Fixture ===&lt;br /&gt;
&lt;br /&gt;
The seven captured queries exercise option lookups, plugin metadata, taxonomy joins, comment counts, search and archives. The data is synthetic, with real WordPress query shapes. It is not a million-post or concurrent-production benchmark. The source WordPress installation identifies itself as 7.1; WordPress/PHP rendering does not execute in the SQL matrix, and installed plugin versions are not performance inputs once these exact queries are captured.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Rows&lt;br /&gt;
|-&lt;br /&gt;
| wp_posts || 22,063&lt;br /&gt;
|-&lt;br /&gt;
| wp_postmeta || 14,013&lt;br /&gt;
|-&lt;br /&gt;
| wp_comments || 6,001&lt;br /&gt;
|-&lt;br /&gt;
| wp_options || 503&lt;br /&gt;
|-&lt;br /&gt;
| wp_terms || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_taxonomy || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_relationships || 7,701&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The corpus contains 2,000 varied generated articles across 16 topics and 20,000 revisions. Titles, excerpts and bodies vary; body lengths range from 396 to 6,996 bytes (median 1,763). The search query uses realistic, present in 80 generated articles; the full query also considers other post types. Low-cardinality fields such as status and categories naturally repeat. This version-2 corpus must not be mixed with older version-1 measurements.&lt;br /&gt;
&lt;br /&gt;
== Correctness and scope ==&lt;br /&gt;
&lt;br /&gt;
Six of the seven exact queries return matching results in all three modes, including the total counts: &#039;&#039;&#039;83&#039;&#039;&#039; for the search and &#039;&#039;&#039;0&#039;&#039;&#039; for the Yoast query. After import, rebuild and restart, all 22,063 post IDs, titles, excerpts and body texts also match a canonical SHA-256 comparison. The previously reported blob-content mismatch and search total of 82 were &#039;&#039;&#039;not reproduced in this fresh master run&#039;&#039;&#039;; they are not carried forward as current failures.&lt;br /&gt;
&lt;br /&gt;
The remaining difference is the taxonomy query. Its exact captured SQL &#039;&#039;&#039;does contain ORDER BY t.name ASC&#039;&#039;&#039;. Both engines return the same 15 projected rows, but in a different name order. MariaDB exposes wp_terms.name as utf8mb4_unicode_520_ci; this fresh MemCP import exposes utf8mb4. Therefore its timing is diagnostic and excluded from accepted speedup claims. This statement applies to this saved query, not to every WordPress taxonomy query. Without an ORDER BY, a different row order alone would not be a correctness failure.&lt;br /&gt;
&lt;br /&gt;
This benchmark does not include the unmerged type/collation fix in PR #871. It reports current master as measured. The taxonomy collation discrepancy remains a migration issue for this schema and should be resolved before relying on equivalent ordering.&lt;br /&gt;
&lt;br /&gt;
These are query-level correctness checks and a post-text integrity check, not an exhaustive application compatibility test. INSERT/UPDATE workloads, parallel PHP requests, maintenance costs, cold starts and HTTP page-load latency are outside this matrix.&lt;br /&gt;
&lt;br /&gt;
== Try MemCP with your PHP hosting ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP is faster on the substantial repeated SQL work measured here. Try it with your own PHP hosting.&#039;&#039;&#039; Start with a copy of your site&#039;s data and replay its frequent queries: counts, searches, archives and plugin joins are useful starting points. Compare complete results and total counts, then measure full uncached HTTP requests and representative writes. You can retain the MySQL wire interface or explore direct PHP hosting to remove transport overhead from many small calls.&lt;br /&gt;
&lt;br /&gt;
WordPress is the example, not the product boundary. The same PHP-folder handler and PDO bridge can host other PHP applications; application and plugin compatibility still needs to be checked for the software you deploy.&lt;br /&gt;
&lt;br /&gt;
== Measurement artifacts and exact queries ==&lt;br /&gt;
&lt;br /&gt;
Local artifact directory: &amp;lt;code&amp;gt;../wordpress-db-lab/measurements/wiki-master-43d0c8140/&amp;lt;/code&amp;gt;. It contains results-master.json (raw batch means and complete query results), php-latency.json (all PHP samples), manifest.json, counts.json, corpus.json, text-parity.json, server logs, and a copied benchmark.py. The SQL runner can be repeated against the same fixture; its WP_BINARY and WP_WORKTREE overrides are for separately labelled candidate checks. Candidate measurements are not included in this master matrix.&lt;br /&gt;
&lt;br /&gt;
Source queries: &amp;lt;code&amp;gt;../wordpress-db-lab/profiles/queries/&amp;lt;/code&amp;gt;. They are reproduced below so that the benchmark shapes, including actual ORDER BY clauses, are unambiguous.&lt;br /&gt;
&lt;br /&gt;
=== Option lookup: siteurl ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Copyright (C) 2026 MemCP WordPress lab contributors&lt;br /&gt;
-- SPDX-License-Identifier: AGPL-3.0-or-later&lt;br /&gt;
SELECT option_value FROM wp_options WHERE option_name = &#039;siteurl&#039; LIMIT 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Elementor metadata join + LIMIT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_elementor_template_type&#039; AND wp_postmeta.meta_value = &#039;landing-page&#039; ) ) AND wp_posts.post_type = &#039;e-landing-page&#039; AND ((wp_posts.post_status &amp;lt;&amp;gt; &#039;trash&#039; AND wp_posts.post_status &amp;lt;&amp;gt; &#039;auto-draft&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Taxonomy DISTINCT/join, ordered by name ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT t.term_id, tr.object_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN (&#039;category&#039;, &#039;post_tag&#039;, &#039;post_format&#039;) AND tr.object_id IN (1, 21993, 21982, 21971, 21960) ORDER BY t.name ASC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Comment count with join ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM wp_comments LEFT JOIN wp_posts AS wp_posts_to_exclude_reviews ON comment_post_ID = wp_posts_to_exclude_reviews.ID WHERE ( comment_approved = &#039;1&#039; ) AND comment_type NOT IN (&#039;note&#039;) AND comment_type != &#039;order_note&#039; AND comment_type != &#039;webhook_delivery&#039; AND comment_type != &#039;action_log&#039; AND wp_posts_to_exclude_reviews.post_type NOT IN (&#039;product&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WordPress search + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND ( wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN (166) ) ) AND (((wp_posts.post_title LIKE &#039;%realistic%&#039;) OR (wp_posts.post_excerpt LIKE &#039;%realistic%&#039;) OR (wp_posts.post_content LIKE &#039;%realistic%&#039;))) AND ((wp_posts.post_type = &#039;attachment&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;e-floating-buttons&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;page&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;post&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;product&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;))) GROUP BY wp_posts.ID ORDER BY wp_posts.post_title LIKE &#039;%realistic%&#039; DESC, wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Yoast CAST metadata join + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_yoast_wpseo_linkdex&#039; AND CAST(wp_postmeta.meta_value AS SIGNED) BETWEEN &#039;1&#039; AND &#039;40&#039; ) ) AND wp_posts.post_type = &#039;post&#039; AND ((wp_posts.post_status = &#039;publish&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Monthly archive DISTINCT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM wp_posts WHERE post_type = &#039;post&#039; AND post_status != &#039;auto-draft&#039; AND post_status != &#039;trash&#039; ORDER BY post_date DESC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=413</id>
		<title>Benchmark MemCP vs. MariaDB on Wordpress</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=413"/>
		<updated>2026-09-09T21:34:24Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 MemCP contributors --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: AGPL-3.0-or-later --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Benchmark MemCP vs. MariaDB on Wordpress =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP makes repeated WordPress database work faster.&#039;&#039;&#039; On current master, MemCP-JIT completes this fixture&#039;s search plus total-count query &#039;&#039;&#039;36.0× faster&#039;&#039;&#039; than MariaDB, its comment count &#039;&#039;&#039;21.1× faster&#039;&#039;&#039;, and its archive query &#039;&#039;&#039;6.2× faster&#039;&#039;&#039;. All six query shapes with matching results have lower warm latency with JIT in this run. The seventh, a taxonomy query, is retained in the matrix with a clearly marked collation mismatch.&lt;br /&gt;
&lt;br /&gt;
MemCP speaks the MySQL protocol and can also &#039;&#039;&#039;host PHP directly in the database process&#039;&#039;&#039;. WordPress is our example application: the hosting interface is general purpose and is also intended for MediaWiki and other PHP software. Try MemCP with your PHP hosting and measure the queries your application actually runs.&lt;br /&gt;
&lt;br /&gt;
== MariaDB vs. MemCP vs. MemCP-JIT ==&lt;br /&gt;
&lt;br /&gt;
Measured on master [https://github.com/launix-de/memcp/commit/43d0c81401616fafeeb456b22f4a47d6e25361d6 43d0c8140], including the SQL literal-parameterization improvement in PR #873. All three columns use the same seven WordPress query shapes and data snapshot. These are &#039;&#039;&#039;warm database round trips&#039;&#039;&#039;, not HTTP page-load times. Lower is better.&lt;br /&gt;
&lt;br /&gt;
Each value is the median of 11 batch means, each containing 100 complete query executions, after 30 warmups. For SQL_CALC_FOUND_ROWS statements, the measured operation also includes the subsequent SELECT FOUND_ROWS() on the same connection.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! Query !! MariaDB (ms) !! MemCP (ms) !! MemCP-JIT (ms) !! MariaDB / JIT !! Result check&lt;br /&gt;
|-&lt;br /&gt;
| Option lookup: siteurl || 0.079 || 0.069 || &#039;&#039;&#039;0.056&#039;&#039;&#039; || 1.39× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| Elementor metadata join + LIMIT || 0.152 || 0.108 || &#039;&#039;&#039;0.079&#039;&#039;&#039; || 1.93× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Taxonomy DISTINCT/join, ordered by name || 0.224 || 0.245 || &#039;&#039;&#039;0.142&#039;&#039;&#039; || Diagnostic only || See correctness notes below&lt;br /&gt;
|-&lt;br /&gt;
| Comment count with join || 3.240 || 0.222 || &#039;&#039;&#039;0.153&#039;&#039;&#039; || 21.14× || Equal; 1 row&lt;br /&gt;
|-&lt;br /&gt;
| WordPress search + FOUND_ROWS || 30.405 || 1.278 || &#039;&#039;&#039;0.844&#039;&#039;&#039; || 36.01× || Equal; 10 rows&lt;br /&gt;
|-&lt;br /&gt;
| Yoast CAST metadata join + FOUND_ROWS || 0.197 || 0.248 || &#039;&#039;&#039;0.144&#039;&#039;&#039; || 1.37× || Equal; 0 rows&lt;br /&gt;
|-&lt;br /&gt;
| Monthly archive DISTINCT || 0.718 || 0.168 || &#039;&#039;&#039;0.116&#039;&#039;&#039; || 6.21× || Equal; 10 rows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The two metadata queries return zero rows on this snapshot. Their times describe proving an empty result, not retrieving a populated plugin workload. Tiny differences in the smallest queries are sensitive to scheduling on this shared development machine. We do not average these seven unrelated query shapes into a single WordPress speedup.&lt;br /&gt;
&lt;br /&gt;
== Host PHP directly: remove a round trip for every small query ==&lt;br /&gt;
&lt;br /&gt;
The optional FrankenPHP dependency supplies the PHP runtime; only MemCP&#039;s own bridge and PDO addon live in this repository. PHP requests use ZTS threads, with OPcache enabled. PHP folders are attached through the existing HTTP handler, alongside the SQL API and dashboard.&lt;br /&gt;
&lt;br /&gt;
With a PHP-enabled build and an external ZTS PHP development installation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
make php PHP_CONFIG=/path/to/zts/php-config&lt;br /&gt;
./memcp-php --no-repl -data /path/to/data --api-port=8098 --mysql-port=3307 --serve=/path/to/php-app lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The application is mounted at /; /dashboard remains available. Scheme code can mount additional applications through servePHP. No WordPress source is bundled into MemCP.&lt;br /&gt;
&lt;br /&gt;
The PDO addon supports authenticated memcp: connections and retains ordinary MySQL wire connections. A mysql: connection to localhost/127.0.0.1 and this MemCP server&#039;s own MySQL port can be routed internally; other destinations continue using their original driver. Both paths require database credentials. WordPress&#039;s use of mysqli is a separate connector question: PDO routing alone is not a claim that every WordPress installation or plugin uses PDO.&lt;br /&gt;
&lt;br /&gt;
A separate microbenchmark measures SELECT 1 inside PHP, using an already established connection. Each round performs 100 warmups and 2,000 measured executions; seven rounds alternate the two transports. The timer includes query(), fetchColumn(), and closeCursor(), but excludes HTTP, connection establishment, and PHP startup. Pdo\Mysql::connect forces the real wire driver for the control, so automatic PDO routing cannot accidentally turn both measurements into RAM calls.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! PHP SELECT 1 transport !! Median of round medians&lt;br /&gt;
|-&lt;br /&gt;
| MySQL wire over local TCP || 37.19 µs&lt;br /&gt;
|-&lt;br /&gt;
| MemCP in-process PDO || &#039;&#039;&#039;11.57 µs&#039;&#039;&#039;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This removes &#039;&#039;&#039;69% of the measured latency&#039;&#039;&#039;, or 25.61 µs per tiny query. At 100 such queries per request, the arithmetic saving is approximately 2.56 ms; at 1,000 queries it is 25.61 ms. Those are extrapolations, not measured WordPress page-load improvements.&lt;br /&gt;
&lt;br /&gt;
For a workload-specific budgeting example, halving 100–200 µs of overhead would save &#039;&#039;&#039;50–100 µs per call (50%)&#039;&#039;&#039;. Across 100 database calls, that would add up to 5–10 ms per request. Those figures illustrate how small savings accumulate; they were not measured here. The measured transport comparison above is the evidence for this setup; measure your own query mix before assigning a per-request saving.&lt;br /&gt;
&lt;br /&gt;
== Reproducible setup ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Item !! Configuration&lt;br /&gt;
|-&lt;br /&gt;
| Measurement date || 9 September 2026 (Europe/Berlin)&lt;br /&gt;
|-&lt;br /&gt;
| CPU || AMD Ryzen 9 7900X3D, 12 physical cores / 24 logical CPUs&lt;br /&gt;
|-&lt;br /&gt;
| Memory / OS || Approximately 62 GiB RAM; Ubuntu 24.04.4 LTS, x86-64&lt;br /&gt;
|-&lt;br /&gt;
| MemCP || Master 43d0c81401616fafeeb456b22f4a47d6e25361d6; unchanged source for both SQL builds&lt;br /&gt;
|-&lt;br /&gt;
| SQL compiler/toolchain || Patched Go 1.27.0, revision 84fe25ee45468f5e3920c11c24e2bbb926fc3a72; GOEXPERIMENT empty vs. GOEXPERIMENT=jit&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB || 10.11.14; query cache OFF; InnoDB buffer pool 128 MiB&lt;br /&gt;
|-&lt;br /&gt;
| PHP microbenchmark || Same MemCP master, built with Go 1.26.0; PHP 8.5.10 ZTS, Zend Engine 4.5.10, OPcache enabled; FrankenPHP v1.12.7; no Go JIT&lt;br /&gt;
|-&lt;br /&gt;
| SQL client || Python 3.12 / PyMySQL, established TCP connections to 127.0.0.1; complete result fetching; no connection setup timed&lt;br /&gt;
|-&lt;br /&gt;
| Database fixture || Read-only consistent snapshot of wordpress_bench_v2, copied to a separate MemCP database; MariaDB InnoDB vs. MemCP sloppy engine; rebuild before measurements&lt;br /&gt;
|-&lt;br /&gt;
| Measurement order || MariaDB, MemCP, MemCP-JIT; one client, no concurrent query load&lt;br /&gt;
|-&lt;br /&gt;
| Runtime settings || Query-plan cache, autoindexing and normal optimizer enabled; TracePrint and ScanDebugging disabled while timing&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This is a warm read comparison, not a matched-memory or durability benchmark. The host is shared with development services; cooperating builds/tests were paused for timing, but CPUs and memory were not reserved or pinned. Autoindexing must have time to activate: the warmup count deliberately exceeds its initial observation threshold. Compiled plans, indexes and maintained group/prejoin structures may all contribute to warm results. Their cold build cost and write-maintenance cost are outside the latency table.&lt;br /&gt;
&lt;br /&gt;
Cold startup and initial automatic structure building are not represented by this table. Both MemCP modes reuse the same freshly imported, rebuilt directory sequentially; persisted structures and OS caches remain available. An earlier preparation pass populated some structures before the final measured run. This is deliberately a warm comparison, not a cold-start A/B test.&lt;br /&gt;
&lt;br /&gt;
=== Fixture ===&lt;br /&gt;
&lt;br /&gt;
The seven captured queries exercise option lookups, plugin metadata, taxonomy joins, comment counts, search and archives. The data is synthetic, with real WordPress query shapes. It is not a million-post or concurrent-production benchmark. The source WordPress installation identifies itself as 7.1; WordPress/PHP rendering does not execute in the SQL matrix, and installed plugin versions are not performance inputs once these exact queries are captured.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table !! Rows&lt;br /&gt;
|-&lt;br /&gt;
| wp_posts || 22,063&lt;br /&gt;
|-&lt;br /&gt;
| wp_postmeta || 14,013&lt;br /&gt;
|-&lt;br /&gt;
| wp_comments || 6,001&lt;br /&gt;
|-&lt;br /&gt;
| wp_options || 503&lt;br /&gt;
|-&lt;br /&gt;
| wp_terms || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_taxonomy || 175&lt;br /&gt;
|-&lt;br /&gt;
| wp_term_relationships || 7,701&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The corpus contains 2,000 varied generated articles across 16 topics and 20,000 revisions. Titles, excerpts and bodies vary; body lengths range from 396 to 6,996 bytes (median 1,764). The search query uses realistic, present in 80 generated articles; the full query also considers other post types. Low-cardinality fields such as status and categories naturally repeat. This version-2 corpus must not be mixed with older version-1 measurements.&lt;br /&gt;
&lt;br /&gt;
== Correctness and scope ==&lt;br /&gt;
&lt;br /&gt;
Six of the seven exact queries return matching results in all three modes, including the total counts: &#039;&#039;&#039;83&#039;&#039;&#039; for the search and &#039;&#039;&#039;0&#039;&#039;&#039; for the Yoast query. After import, rebuild and restart, all 22,063 post IDs, titles, excerpts and body texts also match a canonical SHA-256 comparison. The previously reported blob-content mismatch and search total of 82 were &#039;&#039;&#039;not reproduced in this fresh master run&#039;&#039;&#039;; they are not carried forward as current failures.&lt;br /&gt;
&lt;br /&gt;
The remaining difference is the taxonomy query. Its exact captured SQL &#039;&#039;&#039;does contain ORDER BY t.name ASC&#039;&#039;&#039;. Both engines return the same 15 projected rows, but in a different name order. MariaDB exposes wp_terms.name as utf8mb4_unicode_520_ci; this fresh MemCP import exposes utf8mb4. Therefore its timing is diagnostic and excluded from accepted speedup claims. This statement applies to this saved query, not to every WordPress taxonomy query. Without an ORDER BY, a different row order alone would not be a correctness failure.&lt;br /&gt;
&lt;br /&gt;
This benchmark does not include the unmerged type/collation fix in PR #871. It reports current master as measured. The taxonomy collation discrepancy remains a migration issue for this schema and should be resolved before relying on equivalent ordering.&lt;br /&gt;
&lt;br /&gt;
These are query-level correctness checks and a post-text integrity check, not an exhaustive application compatibility test. INSERT/UPDATE workloads, parallel PHP requests, maintenance costs, cold starts and HTTP page-load latency are outside this matrix.&lt;br /&gt;
&lt;br /&gt;
== Try MemCP with your PHP hosting ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP is faster on the substantial repeated SQL work measured here. Try it with your own PHP hosting.&#039;&#039;&#039; Start with a copy of your site&#039;s data and replay its frequent queries: counts, searches, archives and plugin joins are useful starting points. Compare complete results and total counts, then measure full uncached HTTP requests and representative writes. You can retain the MySQL wire interface or explore direct PHP hosting to remove transport overhead from many small calls.&lt;br /&gt;
&lt;br /&gt;
WordPress is the example, not the product boundary. The same PHP-folder handler and PDO bridge can host other PHP applications; application and plugin compatibility still needs to be checked for the software you deploy.&lt;br /&gt;
&lt;br /&gt;
== Measurement artifacts and exact queries ==&lt;br /&gt;
&lt;br /&gt;
Local artifact directory: &amp;lt;code&amp;gt;../wordpress-db-lab/measurements/wiki-master-43d0c8140/&amp;lt;/code&amp;gt;. It contains results-master.json (raw batch means and complete query results), php-latency.json (all PHP samples), manifest.json, counts.json, server logs, and a copied benchmark.py. The SQL runner can be repeated against the same fixture; its WP_BINARY and WP_WORKTREE overrides are for separately labelled candidate checks. Candidate measurements are not included in this master matrix.&lt;br /&gt;
&lt;br /&gt;
Source queries: &amp;lt;code&amp;gt;../wordpress-db-lab/profiles/queries/&amp;lt;/code&amp;gt;. They are reproduced below so that the benchmark shapes, including actual ORDER BY clauses, are unambiguous.&lt;br /&gt;
&lt;br /&gt;
=== Option lookup: siteurl ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
-- Copyright (C) 2026 MemCP WordPress lab contributors&lt;br /&gt;
-- SPDX-License-Identifier: AGPL-3.0-or-later&lt;br /&gt;
SELECT option_value FROM wp_options WHERE option_name = &#039;siteurl&#039; LIMIT 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Elementor metadata join + LIMIT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_elementor_template_type&#039; AND wp_postmeta.meta_value = &#039;landing-page&#039; ) ) AND wp_posts.post_type = &#039;e-landing-page&#039; AND ((wp_posts.post_status &amp;lt;&amp;gt; &#039;trash&#039; AND wp_posts.post_status &amp;lt;&amp;gt; &#039;auto-draft&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Taxonomy DISTINCT/join, ordered by name ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT t.term_id, tr.object_id FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id INNER JOIN wp_term_relationships AS tr ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN (&#039;category&#039;, &#039;post_tag&#039;, &#039;post_format&#039;) AND tr.object_id IN (1, 21993, 21982, 21971, 21960) ORDER BY t.name ASC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Comment count with join ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT COUNT(*) FROM wp_comments LEFT JOIN wp_posts AS wp_posts_to_exclude_reviews ON comment_post_ID = wp_posts_to_exclude_reviews.ID WHERE ( comment_approved = &#039;1&#039; ) AND comment_type NOT IN (&#039;note&#039;) AND comment_type != &#039;order_note&#039; AND comment_type != &#039;webhook_delivery&#039; AND comment_type != &#039;action_log&#039; AND wp_posts_to_exclude_reviews.post_type NOT IN (&#039;product&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== WordPress search + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND ( wp_posts.ID NOT IN ( SELECT object_id FROM wp_term_relationships WHERE term_taxonomy_id IN (166) ) ) AND (((wp_posts.post_title LIKE &#039;%realistic%&#039;) OR (wp_posts.post_excerpt LIKE &#039;%realistic%&#039;) OR (wp_posts.post_content LIKE &#039;%realistic%&#039;))) AND ((wp_posts.post_type = &#039;attachment&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;e-floating-buttons&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;page&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;post&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;)) OR (wp_posts.post_type = &#039;product&#039; AND (wp_posts.post_status = &#039;publish&#039; OR wp_posts.post_status = &#039;acf-disabled&#039; OR wp_posts.post_status = &#039;private&#039;))) GROUP BY wp_posts.ID ORDER BY wp_posts.post_title LIKE &#039;%realistic%&#039; DESC, wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Yoast CAST metadata join + FOUND_ROWS ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts INNER JOIN wp_postmeta ON ( wp_posts.ID = wp_postmeta.post_id ) WHERE 1=1 AND ( ( wp_postmeta.meta_key = &#039;_yoast_wpseo_linkdex&#039; AND CAST(wp_postmeta.meta_value AS SIGNED) BETWEEN &#039;1&#039; AND &#039;40&#039; ) ) AND wp_posts.post_type = &#039;post&#039; AND ((wp_posts.post_status = &#039;publish&#039;)) GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Monthly archive DISTINCT ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;sql&amp;quot;&amp;gt;&lt;br /&gt;
SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month FROM wp_posts WHERE post_type = &#039;post&#039; AND post_status != &#039;auto-draft&#039; AND post_status != &#039;trash&#039; ORDER BY post_date DESC;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=412</id>
		<title>Benchmark MemCP vs. MariaDB on Wordpress</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Benchmark_MemCP_vs._MariaDB_on_Wordpress&amp;diff=412"/>
		<updated>2026-09-08T18:50:50Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot;&amp;lt;!-- Copyright (C) 2026 MemCP contributors --&amp;gt; &amp;lt;!-- SPDX-License-Identifier: AGPL-3.0-or-later --&amp;gt;  = Benchmark MemCP vs. MariaDB on Wordpress =  WordPress does more than fetch individual posts. Category pages, comment counters, search, archive lists, and plugin metadata queries repeatedly join and aggregate data. These are the places where a different database engine can make a noticeable difference.  We compared &amp;#039;&amp;#039;&amp;#039;MariaDB, MemCP, and MemCP with JIT&amp;#039;&amp;#039;&amp;#039; using seven SQL...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 MemCP contributors --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: AGPL-3.0-or-later --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Benchmark MemCP vs. MariaDB on Wordpress =&lt;br /&gt;
&lt;br /&gt;
WordPress does more than fetch individual posts. Category pages, comment counters, search, archive lists, and plugin metadata queries repeatedly join and aggregate data. These are the places where a different database engine can make a noticeable difference.&lt;br /&gt;
&lt;br /&gt;
We compared &#039;&#039;&#039;MariaDB, MemCP, and MemCP with JIT&#039;&#039;&#039; using seven SQL queries captured from a WordPress installation. On the tested master revision, JIT-enabled MemCP completed the comment-count query &#039;&#039;&#039;25.5 times faster&#039;&#039;&#039; and the archive query &#039;&#039;&#039;4.8 times faster&#039;&#039;&#039; than MariaDB. A simple option lookup was effectively tied. Two small metadata queries still favored MariaDB.&lt;br /&gt;
&lt;br /&gt;
For administrators, the takeaway is specific: &#039;&#039;&#039;MemCP offers substantial potential for recurring aggregates, but the right migration decision depends on your site&#039;s query mix, correctness, and cache behavior—not one headline multiplier.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
| &#039;&#039;&#039;Status of this measurement — 8 September 2026&#039;&#039;&#039;&lt;br /&gt;
The tested master revision has two known correctness issues exposed by this fixture: a blob-reference decoding problem and lost collation in the grouped taxonomy plan. Search also returns an incorrect total count. The affected timings below are diagnostic only, not accepted speedup claims. This is a development benchmark supporting a staging evaluation, &#039;&#039;&#039;not a recommendation to replace a production WordPress database with this revision&#039;&#039;&#039;.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== The results at a glance ==&lt;br /&gt;
&lt;br /&gt;
The following values are &#039;&#039;&#039;warm end-to-end database latency&#039;&#039;&#039;: sending SQL over an established TCP/MySQL connection and receiving the complete result. For the search and SEO queries, the time also includes a subsequent &amp;lt;code&amp;gt;SELECT FOUND_ROWS()&amp;lt;/code&amp;gt; on the same connection.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Lower is better.&#039;&#039;&#039; The comparison column is MariaDB versus MemCP JIT—not JIT versus vanilla.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable sortable&amp;quot;&lt;br /&gt;
! WordPress workload&lt;br /&gt;
! MariaDB&lt;br /&gt;
! MemCP&lt;br /&gt;
! MemCP + JIT&lt;br /&gt;
! MemCP JIT compared with MariaDB&lt;br /&gt;
! Result check&lt;br /&gt;
|-&lt;br /&gt;
| Option lookup (&amp;lt;code&amp;gt;siteurl&amp;lt;/code&amp;gt;)&lt;br /&gt;
| 0.082 ms&lt;br /&gt;
| 0.116 ms&lt;br /&gt;
| 0.081 ms&lt;br /&gt;
| Effectively tied; approximately 1% lower latency&lt;br /&gt;
| Same single row&lt;br /&gt;
|-&lt;br /&gt;
| Plugin metadata join with LIMIT&lt;br /&gt;
| 0.141 ms&lt;br /&gt;
| 0.211 ms&lt;br /&gt;
| 0.200 ms&lt;br /&gt;
| 41.9% higher latency&lt;br /&gt;
| Same empty result&lt;br /&gt;
|-&lt;br /&gt;
| Taxonomy join and DISTINCT&lt;br /&gt;
| 0.222 ms&lt;br /&gt;
| 0.222 ms&lt;br /&gt;
| 0.179 ms&lt;br /&gt;
| Not scored: ordering differs&lt;br /&gt;
| Same 15 rows, different order&lt;br /&gt;
|-&lt;br /&gt;
| Comment COUNT with exclusion join&lt;br /&gt;
| 4.053 ms&lt;br /&gt;
| 0.173 ms&lt;br /&gt;
| &#039;&#039;&#039;0.159 ms&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;25.5× faster; 96.1% lower latency&#039;&#039;&#039;&lt;br /&gt;
| Same aggregate result&lt;br /&gt;
|-&lt;br /&gt;
| WordPress search and total count&lt;br /&gt;
| 31.457 ms&lt;br /&gt;
| 2.192 ms&lt;br /&gt;
| 1.766 ms&lt;br /&gt;
| Not scored: total count differs&lt;br /&gt;
| Same first 10 rows; total 82 instead of 83&lt;br /&gt;
|-&lt;br /&gt;
| SEO metadata CAST/range join&lt;br /&gt;
| 0.177 ms&lt;br /&gt;
| 0.225 ms&lt;br /&gt;
| 0.198 ms&lt;br /&gt;
| 11.8% higher latency&lt;br /&gt;
| Same empty result and total of zero&lt;br /&gt;
|-&lt;br /&gt;
| DISTINCT year/month archive&lt;br /&gt;
| 0.666 ms&lt;br /&gt;
| 0.158 ms&lt;br /&gt;
| &#039;&#039;&#039;0.138 ms&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;4.8× faster; 79.2% lower latency&#039;&#039;&#039;&lt;br /&gt;
| Same 10 ordered rows&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The empty metadata results are intentional disclosures, not successful-hit performance tests. They measure how quickly each engine establishes that there are no matching records in this snapshot. They do not establish performance for populated plugin result sets.&lt;br /&gt;
&lt;br /&gt;
There is no combined “WordPress speedup” score. The frequency of these queries differs between sites, and a correctness failure must not be averaged into a favorable result.&lt;br /&gt;
&lt;br /&gt;
== What this means for a WordPress administrator ==&lt;br /&gt;
&lt;br /&gt;
=== Look for expensive repeated database work ===&lt;br /&gt;
&lt;br /&gt;
A site dominated by indexed point lookups has less to gain from the results here: the option lookup took about 0.08 ms in both MariaDB and JIT-enabled MemCP. A site spending database time on counts, joins, and archive aggregates has a more promising starting point.&lt;br /&gt;
&lt;br /&gt;
For example, the measured comment-count query saves approximately &#039;&#039;&#039;3.89 ms per execution&#039;&#039;&#039;. That can matter if the query is frequent or occurs repeatedly while rendering an uncached request. It does not imply that the entire PHP request becomes 25 times faster.&lt;br /&gt;
&lt;br /&gt;
Use your own slow-query trace or query-monitoring output to identify the statements that dominate database time. Include frontend pages, administration screens, searches, and scheduled plugin work.&lt;br /&gt;
&lt;br /&gt;
=== Understand what is warm ===&lt;br /&gt;
&lt;br /&gt;
MemCP can reuse compiled query plans and incrementally maintained relational structures such as group caches and prejoins. These structures help avoid repeating a join or aggregate from scratch.&lt;br /&gt;
&lt;br /&gt;
A warm read benchmark benefits from that reuse. It does &#039;&#039;&#039;not&#039;&#039;&#039; measure the complete cost of maintaining those structures under writes. New comments, imports, metadata updates, and bulk edits therefore belong in a separate staging test.&lt;br /&gt;
&lt;br /&gt;
JIT is another part of execution: eligible code is compiled to native instructions. It is not permission to change SQL results, and it does not make every query faster. The vanilla column shows that much of the aggregate advantage is already present without JIT.&lt;br /&gt;
&lt;br /&gt;
=== Budget for the first request ===&lt;br /&gt;
&lt;br /&gt;
Fast warm responses do not imply that the first request is equally fast. In this run, selected first-query and warm values were:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Query&lt;br /&gt;
! MemCP first query&lt;br /&gt;
! MemCP + JIT first query&lt;br /&gt;
! MemCP + JIT warm median&lt;br /&gt;
|-&lt;br /&gt;
| Plugin metadata join&lt;br /&gt;
| 42.3 ms&lt;br /&gt;
| 33.2 ms&lt;br /&gt;
| 0.200 ms&lt;br /&gt;
|-&lt;br /&gt;
| Comment COUNT&lt;br /&gt;
| 52.1 ms&lt;br /&gt;
| 66.2 ms&lt;br /&gt;
| 0.159 ms&lt;br /&gt;
|-&lt;br /&gt;
| WordPress search — correctness issue&lt;br /&gt;
| 1,957.7 ms&lt;br /&gt;
| 2,553.0 ms&lt;br /&gt;
| 1.766 ms&lt;br /&gt;
|-&lt;br /&gt;
| Archive&lt;br /&gt;
| 13,652.3 ms&lt;br /&gt;
| 14,560.0 ms&lt;br /&gt;
| 0.138 ms&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Preparation can also occur after the first execution. During the 20 warmup requests, the plugin metadata query had an approximately 650 ms outlier in each MemCP mode; the search had approximately 580 ms outliers.&lt;br /&gt;
&lt;br /&gt;
These are &#039;&#039;&#039;observed first-query latencies after restarting each MemCP process&#039;&#039;&#039;, not a controlled empty-cache comparison: persisted structures and operating-system caches were retained, and vanilla ran before JIT against the same data directory. Server startup itself is not included in these values.&lt;br /&gt;
&lt;br /&gt;
For a migration rehearsal, measure first requests after restart, cache eviction, and representative writes separately. Do not use the warm table to set cold-start service-level expectations.&lt;br /&gt;
&lt;br /&gt;
== A more useful WordPress fixture ==&lt;br /&gt;
&lt;br /&gt;
The queries come from a WordPress installation using common plugins, including WooCommerce, Elementor, Yoast SEO, Advanced Custom Fields, and Contact Form 7. No plugin receives a special place in the scoring; the seven statements cover distinct kinds of database work.&lt;br /&gt;
&lt;br /&gt;
The measured &#039;&#039;&#039;version-2 queryset fixture&#039;&#039;&#039; contains these seven tables—not the complete live WordPress installation:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Table&lt;br /&gt;
! Rows&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;wp_posts&amp;lt;/code&amp;gt;&lt;br /&gt;
| 22,063, including 20,000 revisions&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;wp_postmeta&amp;lt;/code&amp;gt;&lt;br /&gt;
| 14,013&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;wp_comments&amp;lt;/code&amp;gt;&lt;br /&gt;
| 6,001&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;wp_options&amp;lt;/code&amp;gt;&lt;br /&gt;
| 503&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;wp_terms&amp;lt;/code&amp;gt;&lt;br /&gt;
| 175&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;wp_term_taxonomy&amp;lt;/code&amp;gt;&lt;br /&gt;
| 175&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;wp_term_relationships&amp;lt;/code&amp;gt;&lt;br /&gt;
| 7,701&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Version 1 repeated essentially the same search-bearing paragraph in every generated article. Version 2 replaces that with 2,000 different titles, excerpts, and article bodies across 16 topics. Article bodies range from 396 to 6,996 bytes, with a median of 1,764 bytes. Revisions retain their parent document&#039;s content with an editorial change; low-cardinality fields such as status and categories still repeat naturally.&lt;br /&gt;
&lt;br /&gt;
The generator deliberately provides several search frequencies over the 2,000 generated articles:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;nightjar&amp;lt;/code&amp;gt;: 10 matches, or 0.5%;&lt;br /&gt;
* &amp;lt;code&amp;gt;realistic&amp;lt;/code&amp;gt;: 80 matches, or 4%;&lt;br /&gt;
* &amp;lt;code&amp;gt;performance&amp;lt;/code&amp;gt;: 240 matches, or 12%;&lt;br /&gt;
* &amp;lt;code&amp;gt;quasarless&amp;lt;/code&amp;gt;: no matches.&lt;br /&gt;
&lt;br /&gt;
These are corpus checks, &#039;&#039;&#039;not four separately timed search workloads&#039;&#039;&#039;. The captured search query uses &amp;lt;code&amp;gt;realistic&amp;lt;/code&amp;gt;. Its SQL also considers pages and other post types and applies additional predicates, so its complete MariaDB total is 83 rather than 80.&lt;br /&gt;
&lt;br /&gt;
This is a controlled synthetic dataset with real captured query shapes. It is not evidence of performance at millions of posts or under concurrent production traffic. The gains on counts and archives justify testing larger datasets; they do not replace that test.&lt;br /&gt;
&lt;br /&gt;
== Correctness before speed ==&lt;br /&gt;
&lt;br /&gt;
Results were compared across engines, including &amp;lt;code&amp;gt;FOUND_ROWS()&amp;lt;/code&amp;gt; where applicable. Five query shapes agreed; two did not.&lt;br /&gt;
&lt;br /&gt;
=== Taxonomy ordering ===&lt;br /&gt;
&lt;br /&gt;
Both databases expose &amp;lt;code&amp;gt;wp_terms.name&amp;lt;/code&amp;gt; with &amp;lt;code&amp;gt;utf8mb4_unicode_520_ci&amp;lt;/code&amp;gt;. A direct ordered scan agrees, but the full DISTINCT/join plan loses that collation at its grouped sort. For example, MemCP places &amp;lt;code&amp;gt;Uncategorized&amp;lt;/code&amp;gt; before lower-case tag names.&lt;br /&gt;
&lt;br /&gt;
This is &#039;&#039;&#039;not an unspecified tie order&#039;&#039;&#039;. It is a correctness issue, and the taxonomy timing is excluded from speedup claims.&lt;br /&gt;
&lt;br /&gt;
=== Blob content and search totals ===&lt;br /&gt;
&lt;br /&gt;
Full table contents matched checksums immediately after import. After MemCP compaction, 33 long post-content values were observed as 32-byte blob hashes instead of their text. A hash beginning with &amp;lt;code&amp;gt;!&amp;lt;/code&amp;gt; collides with the legacy escaped-string encoding.&lt;br /&gt;
&lt;br /&gt;
For one affected post, MariaDB reports a text length of 5,327 bytes and MemCP reports 32. The search&#039;s first ten rows agree, but MemCP reports 82 total matches versus MariaDB&#039;s 83. Consequently the search timing is also excluded from accepted speedup claims.&lt;br /&gt;
&lt;br /&gt;
These findings must be resolved and the affected workloads revalidated before using this revision for migration. No query was removed from the table to conceal them. All 21 measurements completed without a process crash.&lt;br /&gt;
&lt;br /&gt;
== How the comparison was run ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Item&lt;br /&gt;
! Configuration&lt;br /&gt;
|-&lt;br /&gt;
| MemCP source&lt;br /&gt;
| [https://github.com/launix-de/memcp/commit/ce26bfb3deb883efc09272965cc1a3b9eb177e24 Master ce26bfb3d], including the merged Q1/Q3 planner improvements&lt;br /&gt;
|-&lt;br /&gt;
| Date&lt;br /&gt;
| 8 September 2026&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB&lt;br /&gt;
| 10.11.14; query cache disabled; InnoDB buffer pool 128 MiB&lt;br /&gt;
|-&lt;br /&gt;
| MemCP builds&lt;br /&gt;
| Identical source, both built with the patched Go 1.27.0 toolchain; &amp;lt;code&amp;gt;GOEXPERIMENT&amp;lt;/code&amp;gt; empty versus &amp;lt;code&amp;gt;GOEXPERIMENT=jit&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Host&lt;br /&gt;
| AMD Ryzen 9 7900X3D, 12 cores / 24 logical CPUs; approximately 62 GiB RAM&lt;br /&gt;
|-&lt;br /&gt;
| Client&lt;br /&gt;
| Python/PyMySQL over local TCP; established connections, autocommit&lt;br /&gt;
|-&lt;br /&gt;
| Sampling&lt;br /&gt;
| 20 warmup executions, then 11 batches of 100 executions per query and engine&lt;br /&gt;
|-&lt;br /&gt;
| Reported statistic&lt;br /&gt;
| Median of the 11 batch means, in milliseconds per query or query/FOUND_ROWS pair&lt;br /&gt;
|-&lt;br /&gt;
| Execution order&lt;br /&gt;
| MariaDB, MemCP vanilla, MemCP JIT&lt;br /&gt;
|-&lt;br /&gt;
| Run duration&lt;br /&gt;
| Approximately 93 seconds, excluding builds, fixture import, and investigation&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The host was shared with development work and was not isolated for benchmarking. Small percentage differences should not be overinterpreted. The results are not a memory-budget-matched or concurrency-throughput comparison.&lt;br /&gt;
&lt;br /&gt;
The query-plan cache and normal execution behavior remained enabled. We did not substitute hand-written plans or force a special prejoin before timing. The setup contains no application-level page-cache measurement: this is database latency, not HTTP page-render time.&lt;br /&gt;
&lt;br /&gt;
The measurements are specific to this master snapshot and fixture. Earlier version-1 numbers should not be mixed with this table or used to calculate an improvement attributable solely to a planner patch.&lt;br /&gt;
&lt;br /&gt;
== A practical staging checklist ==&lt;br /&gt;
&lt;br /&gt;
Before deciding whether MemCP will speed up your WordPress installation:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Capture your workload.&#039;&#039;&#039; Include expensive frontend queries, admin pages, search, and the plugins your site actually uses.&lt;br /&gt;
# &#039;&#039;&#039;Use one consistent data snapshot.&#039;&#039;&#039; Preserve IDs, relationships, text, and collations. Compare contents after import and after compression/restart—not just table row counts.&lt;br /&gt;
# &#039;&#039;&#039;Check complete results.&#039;&#039;&#039; Validate ordering, pagination, NULL behavior, aggregates, and total counts, including &amp;lt;code&amp;gt;FOUND_ROWS()&amp;lt;/code&amp;gt;.&lt;br /&gt;
# &#039;&#039;&#039;Separate first use from steady state.&#039;&#039;&#039; Record startup/cache-build spikes, warm medians, and tail latency.&lt;br /&gt;
# &#039;&#039;&#039;Exercise writes and concurrency.&#039;&#039;&#039; Test comments, edits, imports, plugin jobs, cache maintenance, and recovery. This read-only query benchmark does not establish their cost or compatibility.&lt;br /&gt;
# &#039;&#039;&#039;Measure whole requests too.&#039;&#039;&#039; PHP, plugin execution, network requests, and page caching can dominate total page time even when SQL becomes faster.&lt;br /&gt;
# &#039;&#039;&#039;Keep production unchanged until validation passes.&#039;&#039;&#039; Retain your MariaDB deployment and a tested backup/rollback path during evaluation. The known correctness issues above must be closed first.&lt;br /&gt;
&lt;br /&gt;
MemCP&#039;s strongest result here is the reduction of recurring aggregate work from milliseconds to a fraction of a millisecond. For WordPress administrators, that is a concrete reason to evaluate it—but equivalent results and predictable operations remain the entry requirements for any speed claim.&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Main_Page&amp;diff=411</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Main_Page&amp;diff=411"/>
		<updated>2026-09-07T20:48:47Z</updated>

		<summary type="html">&lt;p&gt;Carli: /* Optimizations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 Carl-Philip Haensch --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: GPL-3.0-or-later --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= MemCP Database – Fast, Compressed SQL for OLTP and OLAP =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:2.5rem 2rem; margin:0 0 1.5rem; border-radius:14px; background:linear-gradient(135deg,#3d6208 0%,#64910c 52%,#76b512 100%); color:#fff; text-align:center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:2.6rem; line-height:1.1; font-weight:700; margin-bottom:.7rem;&amp;quot;&amp;gt;MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.45rem; line-height:1.35; font-weight:600; margin:0 auto .9rem; max-width:56rem;&amp;quot;&amp;gt;A fast, compressed, MySQL-protocol-compatible columnar database for modern OLTP and OLAP workloads&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.05rem; line-height:1.6; margin:0 auto 1.4rem; max-width:54rem;&amp;quot;&amp;gt;MemCP is an open-source SQL database written in Go. It combines persistent in-memory operation, adaptive column compression, parallel query execution and direct application APIs so operational data can be queried and analyzed without maintaining a separate analytical copy.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-bottom:1.5rem;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;Beta&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;Open Source&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;MySQL Protocol + HTTP APIs&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;plainlinks&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[[Install MemCP with Docker|&amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border-radius:6px; background:#fff; color:#496f0c; font-weight:700;&amp;quot;&amp;gt;Get started with Docker&amp;lt;/span&amp;gt;]]&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[[Supported SQL|&amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border:1px solid #fff; border-radius:6px; color:#fff; font-weight:700;&amp;quot;&amp;gt;Explore SQL support&amp;lt;/span&amp;gt;]]&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[https://github.com/launix-de/memcp &amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border:1px solid #fff; border-radius:6px; color:#fff; font-weight:700;&amp;quot;&amp;gt;View on GitHub&amp;lt;/span&amp;gt;]&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Memcp-Load.png|center|frameless|1000px|alt=MemCP database dashboard and workload overview]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.85rem 1rem; margin:1rem 0 2rem; border-left:5px solid #d99b00; background:#fff7d6; color:#332600;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Development status: Beta.&#039;&#039;&#039; MemCP is under active development. Check [[Supported SQL]], [[Current Status and Open Issues]] and the durability requirements of your workload before migrating production data.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.15rem; margin:1rem 0 2rem; border-left:5px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Your MySQL queries are too slow?&#039;&#039;&#039; Run the same representative workload on MemCP instead of assuming another index or a larger MySQL server is the only answer. Compare results, durability and authenticated end-to-end latency; if the migration gates pass, move the performance-critical workload to MemCP. [[MySQL is too slow|Start the MemCP performance evaluation →]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.15rem; margin:1rem 0 2rem; border:1px solid #b7c99a; border-radius:9px; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Observed performance profile:&#039;&#039;&#039; MemCP has achieved &#039;&#039;&#039;speedups of 10× and more over MariaDB/PostgreSQL&#039;&#039;&#039; in measured OLAP and search-oriented workflows, where RecSets and compressed column scans avoid wide row materialization. In one filtered-list workflow over roughly one million documents, the same query took around &#039;&#039;&#039;30 seconds on PostgreSQL&#039;&#039;&#039; and &#039;&#039;&#039;1.6 seconds on MemCP&#039;&#039;&#039;. Isolated OLTP paths currently take about &#039;&#039;&#039;1.3–2.0× as long&#039;&#039;&#039;, but in complete WordPress- and wiki-style page builds this has made &#039;&#039;&#039;no significant difference to overall page-loading time&#039;&#039;&#039; in the measured application workflows. These are workload observations, not universal guarantees; [[Performance Measurement|reproduce them on your data]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What is MemCP? ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP Database&#039;&#039;&#039; is a persistent, compressed, column-oriented SQL database for mixed OLTP and OLAP workloads. It speaks the MySQL client protocol, also exposes SQL over HTTP, and executes supported queries through a functional compiler and a parallel column-storage engine.&lt;br /&gt;
&lt;br /&gt;
The name on this site refers to the database project. MemCP Database is &#039;&#039;&#039;not&#039;&#039;&#039; a Model Context Protocol (MCP) memory server and is unrelated to the C/C++ &amp;lt;code&amp;gt;memcpy()&amp;lt;/code&amp;gt; memory-copy function. When writing about or linking to the project, the unambiguous name is &#039;&#039;&#039;MemCP Database&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Problems MemCP solves ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:1rem; margin:1rem 0 2rem;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.1rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Slow filtered lists on millions of rows&amp;lt;/div&amp;gt;&lt;br /&gt;
Complex &amp;lt;code&amp;gt;WHERE&amp;lt;/code&amp;gt;, joins, membership tests, &amp;lt;code&amp;gt;ORDER BY&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LIMIT&amp;lt;/code&amp;gt; can make a row store inspect or materialize far more data than the page returns. MemCP uses RecSets, late materialization, adaptive indexes and ordered braking to keep the working domain compact.&amp;lt;br /&amp;gt;[[MySQL is too slow|Evaluate the query]] · [[RecSets|How RecSets work]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.1rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Slow GROUP BY, COUNT and dashboards&amp;lt;/div&amp;gt;&lt;br /&gt;
Column scans read only referenced compressed values. Parallel shard-local aggregation, group caches and computed structures target repeated analytical queries over fresh operational data.&amp;lt;br /&amp;gt;[[Columnar Storage]] · [[Temporary Computed Columns]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.1rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Slow database writes caused by fsync&amp;lt;/div&amp;gt;&lt;br /&gt;
Durability is selectable per table. &amp;lt;code&amp;gt;safe&amp;lt;/code&amp;gt; protects commits through power loss; &amp;lt;code&amp;gt;logged&amp;lt;/code&amp;gt; has measured about 10× its write throughput when process-crash recovery is sufficient.&amp;lt;br /&amp;gt;[[Persistency and Performance Guarantees|Choose a write strategy]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.1rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Database writes wear out an SD card&amp;lt;/div&amp;gt;&lt;br /&gt;
For reconstructible edge data, &amp;lt;code&amp;gt;sloppy&amp;lt;/code&amp;gt; avoids a continuous WAL and normally publishes one compressed generation every 15 minutes, reducing constant flash writes while making the loss window explicit.&amp;lt;br /&amp;gt;[[Hardware Requirements]] · [[Persistency and Performance Guarantees]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Choose your path ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:1rem; margin:1rem 0 2rem;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Evaluate MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
Understand the workload model, current status, hardware needs and differences from MySQL.&lt;br /&gt;
&lt;br /&gt;
[[What is OLTP and OLAP|OLTP and OLAP]] · [[Comparison: MemCP vs. MySQL|Compare with MySQL]] · [[Hardware Requirements|Hardware requirements]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Build an application&amp;lt;/div&amp;gt;&lt;br /&gt;
Use the MySQL protocol, SQL over HTTP, RDF or application-specific endpoints inside MemCP.&lt;br /&gt;
&lt;br /&gt;
[[Advanced SQL Tutorial|SQL tutorial]] · [[SQL over REST|SQL over HTTP]] · [[Database Tools compatibility with MemCP|Client tooling]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Operate MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
Plan deployment, migration, persistence, storage backends, settings and performance measurement.&lt;br /&gt;
&lt;br /&gt;
[[Deployment]] · [[Persistency and Performance Guarantees|Durability]] · [[Migration from MySQL and PostgreSQL|Migration]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Understand and contribute&amp;lt;/div&amp;gt;&lt;br /&gt;
Explore the storage engine, optimizer, embedded Scheme runtime and project internals.&lt;br /&gt;
&lt;br /&gt;
[[Query Planner and Physical Lowering|Query planner]] · [[RecSets]] · [[Columnar Storage]] · [[Contributing]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
=== Run with Docker ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
docker run --name memcp \&lt;br /&gt;
  -e ROOT_PASSWORD=&#039;choose-a-password&#039; \&lt;br /&gt;
  -p 4321:4321 -p 3307:3307 \&lt;br /&gt;
  -v memcp-data:/data \&lt;br /&gt;
  carli2/memcp:latest&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then open &amp;lt;code&amp;gt;http://localhost:4321&amp;lt;/code&amp;gt; and connect a MySQL application to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on port &#039;&#039;&#039;3307&#039;&#039;&#039;. The volume mounted at &amp;lt;code&amp;gt;/data&amp;lt;/code&amp;gt; retains persistent table data across container replacement. See [[Install MemCP with Docker|the complete Docker guide]] before deploying it as a service.&lt;br /&gt;
&lt;br /&gt;
=== Build from source ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/launix-de/memcp&lt;br /&gt;
cd memcp&lt;br /&gt;
go mod download&lt;br /&gt;
make&lt;br /&gt;
./memcp --api-port=4321 --mysql-port=3307 lib/main.scm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connect with MySQL tooling:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -h 127.0.0.1 -u root -p -P 3307&lt;br /&gt;
# Enter the password selected for this data directory.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The development default for a fresh data directory is &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt;. Change it before exposing MemCP to another machine. MemCP can also be supervised with PM2:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pm2 start ./memcp --name memcp -- \&lt;br /&gt;
  --no-repl -data ./data --api-port=4321 --mysql-port=3307 lib/main.scm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Background deployments must use &amp;lt;code&amp;gt;--no-repl&amp;lt;/code&amp;gt; so that closing standard input does not terminate the interactive console and stop the server. See [[Compile MemCP from Source|Build from Source]], [[Deployment]] and [[MemCP Console]].&lt;br /&gt;
&lt;br /&gt;
== Key features ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:.8rem; margin:1rem 0;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;High performance&#039;&#039;&#039;&amp;lt;br /&amp;gt;Parallel, batch-oriented query execution is designed for multicore CPUs, compact working sets and fast persistent storage, serving both OLTP and OLAP workloads.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Columnar storage&#039;&#039;&#039;&amp;lt;br /&amp;gt;Data is stored by column for improved compression, a smaller memory footprint and fast analytical access.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Persistent in-memory operation&#039;&#039;&#039;&amp;lt;br /&amp;gt;MemCP is designed to keep active data in memory while offering configurable per-table durability and persistence backends.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Fast configurable writes&#039;&#039;&#039;&amp;lt;br /&amp;gt;Choose durability per table: &amp;lt;code&amp;gt;safe&amp;lt;/code&amp;gt; protects committed data through power loss, while measured &amp;lt;code&amp;gt;logged&amp;lt;/code&amp;gt; paths have reached about 10× its write throughput; &amp;lt;code&amp;gt;sloppy&amp;lt;/code&amp;gt; batches reconstructible data into the normal 15-minute rebuild cycle.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Built-in APIs&#039;&#039;&#039;&amp;lt;br /&amp;gt;SQL over HTTP and in-database services can remove an extra middleware hop for suitable applications.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Adaptive compression&#039;&#039;&#039;&amp;lt;br /&amp;gt;Bit-packing, dictionary encoding and sequence compression reduce the bytes read for suitable data. Historical imports have reached reductions around 80% versus their MySQL/MariaDB representation; measure your own schema.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Simple deployment&#039;&#039;&#039;&amp;lt;br /&amp;gt;Start with Docker, PM2 or the native binary. The compact application has historically had an installation footprint of approximately 10 MB.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Extensible frontends&#039;&#039;&#039;&amp;lt;br /&amp;gt;The Go storage engine and embedded Scheme environment support SQL, RDF, REST and custom application interfaces.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #9ad32d; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Cost-based query execution&#039;&#039;&#039;&amp;lt;br /&amp;gt;Logical decorrelation and join optimization are separated from cost-based physical selection of scans, indexes, RecSets, reusable caches and execution pipelines.&amp;lt;br /&amp;gt;[[Query Planner and Physical Lowering|How MemCP plans and lowers queries →]] · [[RecSets|How compact record sets process large domains →]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why MemCP? ==&lt;br /&gt;
&lt;br /&gt;
Traditional relational databases were designed around spinning disks and comparatively small numbers of CPU cores. MemCP rethinks storage and query execution for modern multicore systems, large caches, fast storage and mixed workloads.&lt;br /&gt;
&lt;br /&gt;
Typical use cases include:&lt;br /&gt;
&lt;br /&gt;
* real-time dashboards and analytics;&lt;br /&gt;
* data-heavy SaaS platforms;&lt;br /&gt;
* embedded systems with limited resources;&lt;br /&gt;
* high-throughput OLTP/OLAP hybrids.&lt;br /&gt;
&lt;br /&gt;
Whether MemCP is a good fit depends on the required SQL compatibility, durability, query mix, data size and operational environment. Review [[Supported SQL]], [[Persistency and Performance Guarantees]] and [[Performance Measurement]] rather than treating benchmark figures as universal guarantees.&lt;br /&gt;
&lt;br /&gt;
== MemCP vs. MySQL ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
! Feature&lt;br /&gt;
! MySQL&lt;br /&gt;
! MemCP&lt;br /&gt;
|-&lt;br /&gt;
| Storage model&lt;br /&gt;
| Primarily row-based&lt;br /&gt;
| Column-based and compressed&lt;br /&gt;
|-&lt;br /&gt;
| Performance focus&lt;br /&gt;
| General-purpose relational workloads&lt;br /&gt;
| Parallel, in-memory-oriented execution for mixed operational and analytical workloads&lt;br /&gt;
|-&lt;br /&gt;
| In-memory capability&lt;br /&gt;
| Available through selected engines and caching&lt;br /&gt;
| Central design goal and default operating model&lt;br /&gt;
|-&lt;br /&gt;
| REST API integration&lt;br /&gt;
| Normally external&lt;br /&gt;
| Built in&lt;br /&gt;
|-&lt;br /&gt;
| Installation footprint&lt;br /&gt;
| Common server installations are approximately 150 MB or larger&lt;br /&gt;
| The native application has historically been approximately 10 MB&lt;br /&gt;
|-&lt;br /&gt;
| Open source&lt;br /&gt;
| ✅&lt;br /&gt;
| ✅&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
MemCP provides MySQL protocol compatibility but does not claim to implement every MySQL feature. See [[Comparison: MemCP vs. MySQL]] for a detailed comparison and [[Database Tools compatibility with MemCP]] for client compatibility.&lt;br /&gt;
&lt;br /&gt;
== Architecture overview ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tables, schemas and columns&#039;&#039;&#039;: Familiar SQL structures use a compressed columnar physical layout. See [[Databases, Tables and Columns]] and [[Columnar Storage]].&lt;br /&gt;
* &#039;&#039;&#039;Transaction model&#039;&#039;&#039;: Delta and main storage support mixed OLTP and OLAP semantics. See [[Transactions and Isolation]] and [[Shards, RecordIDs, Main Storage, Delta Storage]].&lt;br /&gt;
* &#039;&#039;&#039;Query planning&#039;&#039;&#039;: Logical optimization is separated from physical execution decisions. See [[Query Planner and Physical Lowering]].&lt;br /&gt;
* &#039;&#039;&#039;Persistence&#039;&#039;&#039;: Per-table durability can use filesystem, S3 or Ceph/RADOS storage. See [[Persistency and Performance Guarantees]] and [[Storage Backends]].&lt;br /&gt;
* &#039;&#039;&#039;Operations&#039;&#039;&#039;: The dashboard, metrics, process inspection and memory controls support day-to-day operation. See [[Dashboard and Operations]] and [[Memory Management and Eviction]].&lt;br /&gt;
* &#039;&#039;&#039;Scale-out roadmap&#039;&#039;&#039;: MemCP is single-node today. A leaderless CRUSH/RADOS and MOESI-inspired cluster design is planned, but must not be treated as an available production feature. See [[Cluster Monitor]].&lt;br /&gt;
* &#039;&#039;&#039;Frontends&#039;&#039;&#039;: MemCP provides multiple query and application interfaces:&lt;br /&gt;
** SQL through the MySQL wire protocol and SQL over HTTP;&lt;br /&gt;
** an RDF/graph query frontend;&lt;br /&gt;
** custom APIs through in-database web applications.&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
The following navigation remains on the start page so users and search engines can reach every major documentation area directly.&lt;br /&gt;
&lt;br /&gt;
=== Introduction and evaluation ===&lt;br /&gt;
&lt;br /&gt;
* [[What is OLTP and OLAP]]&lt;br /&gt;
* [[History of the MemCP project]]&lt;br /&gt;
* [[Hardware Requirements]]&lt;br /&gt;
* [[Persistency and Performance Guarantees]]&lt;br /&gt;
* [[Current Status and Open Issues]]&lt;br /&gt;
* [[MySQL is too slow|SQL performance problems MemCP solves]]&lt;br /&gt;
* [[Comparison: MemCP vs. MySQL]]&lt;br /&gt;
&lt;br /&gt;
=== Getting started ===&lt;br /&gt;
&lt;br /&gt;
* [[Install MemCP with Docker|Install with Docker]]&lt;br /&gt;
* [[With Singularity|Install with Singularity/Apptainer]]&lt;br /&gt;
* [[Compile MemCP from Source|Build from Source]]&lt;br /&gt;
* [[Contributing]]&lt;br /&gt;
* [[Introduction to Scheme]]&lt;br /&gt;
* [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
=== Administration ===&lt;br /&gt;
&lt;br /&gt;
* [[Deployment]]&lt;br /&gt;
* [[Migration from MySQL and PostgreSQL]]&lt;br /&gt;
* [[Settings]]&lt;br /&gt;
* [[Security and Authentication]]&lt;br /&gt;
* [[Dashboard and Operations]]&lt;br /&gt;
* [[Memory Management and Eviction]]&lt;br /&gt;
* [[Process Hibernation]]&lt;br /&gt;
* [[Performance Measurement]]&lt;br /&gt;
* [[MemCP Console]]&lt;br /&gt;
&lt;br /&gt;
=== Frontends ===&lt;br /&gt;
&lt;br /&gt;
==== SQL frontend ====&lt;br /&gt;
&lt;br /&gt;
* [[Supported SQL]]&lt;br /&gt;
* [[Advanced SQL Tutorial]]&lt;br /&gt;
* [[JSON|JSON and SQL/JSON]]&lt;br /&gt;
* [[Triggers]]&lt;br /&gt;
* [[SQL over REST]]&lt;br /&gt;
* [[Database Tools compatibility with MemCP|Supported Tooling]]&lt;br /&gt;
* [[Query Planner and Physical Lowering|How SQL operators are implemented]]&lt;br /&gt;
* [[Add custom SQL operators to MemCP]]&lt;br /&gt;
&lt;br /&gt;
==== RDF frontend ====&lt;br /&gt;
&lt;br /&gt;
* [[Introduction to RDF]]&lt;br /&gt;
* [[Advanced Graph Querying]]&lt;br /&gt;
* [https://github.com/launix-de/rdfop RDF browser and templating example]&lt;br /&gt;
&lt;br /&gt;
==== Custom frontends ====&lt;br /&gt;
&lt;br /&gt;
* [[In-Database WebApps and REST Services]]&lt;br /&gt;
* [[MemCP for Microservices]]&lt;br /&gt;
* [[Websockets in MemCP]]&lt;br /&gt;
&lt;br /&gt;
=== Persistence backends and storage ===&lt;br /&gt;
&lt;br /&gt;
* [[File System]]&lt;br /&gt;
* [[Storage Backends|S3-compatible and Ceph/RADOS storage]]&lt;br /&gt;
* [[Cluster Monitor]]&lt;br /&gt;
&lt;br /&gt;
=== Internals ===&lt;br /&gt;
&lt;br /&gt;
==== How MemCP works ====&lt;br /&gt;
&lt;br /&gt;
* [[Databases, Tables and Columns]]&lt;br /&gt;
* [[Shards, RecordIDs, Main Storage, Delta Storage]]&lt;br /&gt;
* [[Columnar Storage]]&lt;br /&gt;
* [[Transactions and Isolation]]&lt;br /&gt;
* [[Query Planner and Physical Lowering]]&lt;br /&gt;
* [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
==== Scheme documentation ====&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
&lt;br /&gt;
==== Optimizations ====&lt;br /&gt;
&lt;br /&gt;
* [[Benchmark MemCP vs. MariaDB on Wordpress|Benchmarks]]&lt;br /&gt;
* [[Query Planner and Physical Lowering]]&lt;br /&gt;
* [[In-Memory Compression, Columnar Compression Techniques]]&lt;br /&gt;
* [[Temporary Computed Columns]]&lt;br /&gt;
* [[Data Auto Sharding and Auto Indexing]]&lt;br /&gt;
* [[Parallel Computing]]&lt;br /&gt;
&lt;br /&gt;
== Further reading ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/launix-de/memcp MemCP on GitHub]&lt;br /&gt;
* [https://www.vldb.org/pvldb/vol13/p2649-boncz.pdf VLDB Research Paper]&lt;br /&gt;
* [https://cs.emis.de/LNI/Proceedings/Proceedings241/383.pdf LNI Proceedings Paper]&lt;br /&gt;
* [https://www.dcs.bbk.ac.uk/~dell/teaching/cc/paper/sigmod10/p135-malewicz.pdf Large Graph Algorithms]&lt;br /&gt;
&lt;br /&gt;
Additional blog posts on design decisions, compression techniques and performance optimization are available on the [https://launix.de/launix/ Launix blog].&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
&lt;br /&gt;
MemCP is an open-source project maintained by developers for developers. Contributions are welcome in the form of bug reports, feature requests and pull requests.&lt;br /&gt;
&lt;br /&gt;
See [[Contributing]] and the [https://github.com/launix-de/memcp GitHub repository].&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Main_Page&amp;diff=410</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Main_Page&amp;diff=410"/>
		<updated>2026-09-07T20:48:15Z</updated>

		<summary type="html">&lt;p&gt;Carli: /* Optimizations */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 Carl-Philip Haensch --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: GPL-3.0-or-later --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= MemCP Database – Fast, Compressed SQL for OLTP and OLAP =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:2.5rem 2rem; margin:0 0 1.5rem; border-radius:14px; background:linear-gradient(135deg,#3d6208 0%,#64910c 52%,#76b512 100%); color:#fff; text-align:center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:2.6rem; line-height:1.1; font-weight:700; margin-bottom:.7rem;&amp;quot;&amp;gt;MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.45rem; line-height:1.35; font-weight:600; margin:0 auto .9rem; max-width:56rem;&amp;quot;&amp;gt;A fast, compressed, MySQL-protocol-compatible columnar database for modern OLTP and OLAP workloads&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.05rem; line-height:1.6; margin:0 auto 1.4rem; max-width:54rem;&amp;quot;&amp;gt;MemCP is an open-source SQL database written in Go. It combines persistent in-memory operation, adaptive column compression, parallel query execution and direct application APIs so operational data can be queried and analyzed without maintaining a separate analytical copy.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-bottom:1.5rem;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;Beta&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;Open Source&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;MySQL Protocol + HTTP APIs&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;plainlinks&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[[Install MemCP with Docker|&amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border-radius:6px; background:#fff; color:#496f0c; font-weight:700;&amp;quot;&amp;gt;Get started with Docker&amp;lt;/span&amp;gt;]]&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[[Supported SQL|&amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border:1px solid #fff; border-radius:6px; color:#fff; font-weight:700;&amp;quot;&amp;gt;Explore SQL support&amp;lt;/span&amp;gt;]]&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[https://github.com/launix-de/memcp &amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border:1px solid #fff; border-radius:6px; color:#fff; font-weight:700;&amp;quot;&amp;gt;View on GitHub&amp;lt;/span&amp;gt;]&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Memcp-Load.png|center|frameless|1000px|alt=MemCP database dashboard and workload overview]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.85rem 1rem; margin:1rem 0 2rem; border-left:5px solid #d99b00; background:#fff7d6; color:#332600;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Development status: Beta.&#039;&#039;&#039; MemCP is under active development. Check [[Supported SQL]], [[Current Status and Open Issues]] and the durability requirements of your workload before migrating production data.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.15rem; margin:1rem 0 2rem; border-left:5px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Your MySQL queries are too slow?&#039;&#039;&#039; Run the same representative workload on MemCP instead of assuming another index or a larger MySQL server is the only answer. Compare results, durability and authenticated end-to-end latency; if the migration gates pass, move the performance-critical workload to MemCP. [[MySQL is too slow|Start the MemCP performance evaluation →]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.15rem; margin:1rem 0 2rem; border:1px solid #b7c99a; border-radius:9px; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Observed performance profile:&#039;&#039;&#039; MemCP has achieved &#039;&#039;&#039;speedups of 10× and more over MariaDB/PostgreSQL&#039;&#039;&#039; in measured OLAP and search-oriented workflows, where RecSets and compressed column scans avoid wide row materialization. In one filtered-list workflow over roughly one million documents, the same query took around &#039;&#039;&#039;30 seconds on PostgreSQL&#039;&#039;&#039; and &#039;&#039;&#039;1.6 seconds on MemCP&#039;&#039;&#039;. Isolated OLTP paths currently take about &#039;&#039;&#039;1.3–2.0× as long&#039;&#039;&#039;, but in complete WordPress- and wiki-style page builds this has made &#039;&#039;&#039;no significant difference to overall page-loading time&#039;&#039;&#039; in the measured application workflows. These are workload observations, not universal guarantees; [[Performance Measurement|reproduce them on your data]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What is MemCP? ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP Database&#039;&#039;&#039; is a persistent, compressed, column-oriented SQL database for mixed OLTP and OLAP workloads. It speaks the MySQL client protocol, also exposes SQL over HTTP, and executes supported queries through a functional compiler and a parallel column-storage engine.&lt;br /&gt;
&lt;br /&gt;
The name on this site refers to the database project. MemCP Database is &#039;&#039;&#039;not&#039;&#039;&#039; a Model Context Protocol (MCP) memory server and is unrelated to the C/C++ &amp;lt;code&amp;gt;memcpy()&amp;lt;/code&amp;gt; memory-copy function. When writing about or linking to the project, the unambiguous name is &#039;&#039;&#039;MemCP Database&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Problems MemCP solves ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(240px,1fr)); gap:1rem; margin:1rem 0 2rem;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.1rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Slow filtered lists on millions of rows&amp;lt;/div&amp;gt;&lt;br /&gt;
Complex &amp;lt;code&amp;gt;WHERE&amp;lt;/code&amp;gt;, joins, membership tests, &amp;lt;code&amp;gt;ORDER BY&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;LIMIT&amp;lt;/code&amp;gt; can make a row store inspect or materialize far more data than the page returns. MemCP uses RecSets, late materialization, adaptive indexes and ordered braking to keep the working domain compact.&amp;lt;br /&amp;gt;[[MySQL is too slow|Evaluate the query]] · [[RecSets|How RecSets work]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.1rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Slow GROUP BY, COUNT and dashboards&amp;lt;/div&amp;gt;&lt;br /&gt;
Column scans read only referenced compressed values. Parallel shard-local aggregation, group caches and computed structures target repeated analytical queries over fresh operational data.&amp;lt;br /&amp;gt;[[Columnar Storage]] · [[Temporary Computed Columns]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.1rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Slow database writes caused by fsync&amp;lt;/div&amp;gt;&lt;br /&gt;
Durability is selectable per table. &amp;lt;code&amp;gt;safe&amp;lt;/code&amp;gt; protects commits through power loss; &amp;lt;code&amp;gt;logged&amp;lt;/code&amp;gt; has measured about 10× its write throughput when process-crash recovery is sufficient.&amp;lt;br /&amp;gt;[[Persistency and Performance Guarantees|Choose a write strategy]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.1rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Database writes wear out an SD card&amp;lt;/div&amp;gt;&lt;br /&gt;
For reconstructible edge data, &amp;lt;code&amp;gt;sloppy&amp;lt;/code&amp;gt; avoids a continuous WAL and normally publishes one compressed generation every 15 minutes, reducing constant flash writes while making the loss window explicit.&amp;lt;br /&amp;gt;[[Hardware Requirements]] · [[Persistency and Performance Guarantees]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Choose your path ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:1rem; margin:1rem 0 2rem;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Evaluate MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
Understand the workload model, current status, hardware needs and differences from MySQL.&lt;br /&gt;
&lt;br /&gt;
[[What is OLTP and OLAP|OLTP and OLAP]] · [[Comparison: MemCP vs. MySQL|Compare with MySQL]] · [[Hardware Requirements|Hardware requirements]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Build an application&amp;lt;/div&amp;gt;&lt;br /&gt;
Use the MySQL protocol, SQL over HTTP, RDF or application-specific endpoints inside MemCP.&lt;br /&gt;
&lt;br /&gt;
[[Advanced SQL Tutorial|SQL tutorial]] · [[SQL over REST|SQL over HTTP]] · [[Database Tools compatibility with MemCP|Client tooling]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Operate MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
Plan deployment, migration, persistence, storage backends, settings and performance measurement.&lt;br /&gt;
&lt;br /&gt;
[[Deployment]] · [[Persistency and Performance Guarantees|Durability]] · [[Migration from MySQL and PostgreSQL|Migration]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Understand and contribute&amp;lt;/div&amp;gt;&lt;br /&gt;
Explore the storage engine, optimizer, embedded Scheme runtime and project internals.&lt;br /&gt;
&lt;br /&gt;
[[Query Planner and Physical Lowering|Query planner]] · [[RecSets]] · [[Columnar Storage]] · [[Contributing]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
=== Run with Docker ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
docker run --name memcp \&lt;br /&gt;
  -e ROOT_PASSWORD=&#039;choose-a-password&#039; \&lt;br /&gt;
  -p 4321:4321 -p 3307:3307 \&lt;br /&gt;
  -v memcp-data:/data \&lt;br /&gt;
  carli2/memcp:latest&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then open &amp;lt;code&amp;gt;http://localhost:4321&amp;lt;/code&amp;gt; and connect a MySQL application to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on port &#039;&#039;&#039;3307&#039;&#039;&#039;. The volume mounted at &amp;lt;code&amp;gt;/data&amp;lt;/code&amp;gt; retains persistent table data across container replacement. See [[Install MemCP with Docker|the complete Docker guide]] before deploying it as a service.&lt;br /&gt;
&lt;br /&gt;
=== Build from source ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/launix-de/memcp&lt;br /&gt;
cd memcp&lt;br /&gt;
go mod download&lt;br /&gt;
make&lt;br /&gt;
./memcp --api-port=4321 --mysql-port=3307 lib/main.scm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connect with MySQL tooling:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -h 127.0.0.1 -u root -p -P 3307&lt;br /&gt;
# Enter the password selected for this data directory.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The development default for a fresh data directory is &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt;. Change it before exposing MemCP to another machine. MemCP can also be supervised with PM2:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
pm2 start ./memcp --name memcp -- \&lt;br /&gt;
  --no-repl -data ./data --api-port=4321 --mysql-port=3307 lib/main.scm&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Background deployments must use &amp;lt;code&amp;gt;--no-repl&amp;lt;/code&amp;gt; so that closing standard input does not terminate the interactive console and stop the server. See [[Compile MemCP from Source|Build from Source]], [[Deployment]] and [[MemCP Console]].&lt;br /&gt;
&lt;br /&gt;
== Key features ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:.8rem; margin:1rem 0;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;High performance&#039;&#039;&#039;&amp;lt;br /&amp;gt;Parallel, batch-oriented query execution is designed for multicore CPUs, compact working sets and fast persistent storage, serving both OLTP and OLAP workloads.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Columnar storage&#039;&#039;&#039;&amp;lt;br /&amp;gt;Data is stored by column for improved compression, a smaller memory footprint and fast analytical access.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Persistent in-memory operation&#039;&#039;&#039;&amp;lt;br /&amp;gt;MemCP is designed to keep active data in memory while offering configurable per-table durability and persistence backends.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Fast configurable writes&#039;&#039;&#039;&amp;lt;br /&amp;gt;Choose durability per table: &amp;lt;code&amp;gt;safe&amp;lt;/code&amp;gt; protects committed data through power loss, while measured &amp;lt;code&amp;gt;logged&amp;lt;/code&amp;gt; paths have reached about 10× its write throughput; &amp;lt;code&amp;gt;sloppy&amp;lt;/code&amp;gt; batches reconstructible data into the normal 15-minute rebuild cycle.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Built-in APIs&#039;&#039;&#039;&amp;lt;br /&amp;gt;SQL over HTTP and in-database services can remove an extra middleware hop for suitable applications.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Adaptive compression&#039;&#039;&#039;&amp;lt;br /&amp;gt;Bit-packing, dictionary encoding and sequence compression reduce the bytes read for suitable data. Historical imports have reached reductions around 80% versus their MySQL/MariaDB representation; measure your own schema.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Simple deployment&#039;&#039;&#039;&amp;lt;br /&amp;gt;Start with Docker, PM2 or the native binary. The compact application has historically had an installation footprint of approximately 10 MB.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Extensible frontends&#039;&#039;&#039;&amp;lt;br /&amp;gt;The Go storage engine and embedded Scheme environment support SQL, RDF, REST and custom application interfaces.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #9ad32d; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Cost-based query execution&#039;&#039;&#039;&amp;lt;br /&amp;gt;Logical decorrelation and join optimization are separated from cost-based physical selection of scans, indexes, RecSets, reusable caches and execution pipelines.&amp;lt;br /&amp;gt;[[Query Planner and Physical Lowering|How MemCP plans and lowers queries →]] · [[RecSets|How compact record sets process large domains →]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why MemCP? ==&lt;br /&gt;
&lt;br /&gt;
Traditional relational databases were designed around spinning disks and comparatively small numbers of CPU cores. MemCP rethinks storage and query execution for modern multicore systems, large caches, fast storage and mixed workloads.&lt;br /&gt;
&lt;br /&gt;
Typical use cases include:&lt;br /&gt;
&lt;br /&gt;
* real-time dashboards and analytics;&lt;br /&gt;
* data-heavy SaaS platforms;&lt;br /&gt;
* embedded systems with limited resources;&lt;br /&gt;
* high-throughput OLTP/OLAP hybrids.&lt;br /&gt;
&lt;br /&gt;
Whether MemCP is a good fit depends on the required SQL compatibility, durability, query mix, data size and operational environment. Review [[Supported SQL]], [[Persistency and Performance Guarantees]] and [[Performance Measurement]] rather than treating benchmark figures as universal guarantees.&lt;br /&gt;
&lt;br /&gt;
== MemCP vs. MySQL ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
! Feature&lt;br /&gt;
! MySQL&lt;br /&gt;
! MemCP&lt;br /&gt;
|-&lt;br /&gt;
| Storage model&lt;br /&gt;
| Primarily row-based&lt;br /&gt;
| Column-based and compressed&lt;br /&gt;
|-&lt;br /&gt;
| Performance focus&lt;br /&gt;
| General-purpose relational workloads&lt;br /&gt;
| Parallel, in-memory-oriented execution for mixed operational and analytical workloads&lt;br /&gt;
|-&lt;br /&gt;
| In-memory capability&lt;br /&gt;
| Available through selected engines and caching&lt;br /&gt;
| Central design goal and default operating model&lt;br /&gt;
|-&lt;br /&gt;
| REST API integration&lt;br /&gt;
| Normally external&lt;br /&gt;
| Built in&lt;br /&gt;
|-&lt;br /&gt;
| Installation footprint&lt;br /&gt;
| Common server installations are approximately 150 MB or larger&lt;br /&gt;
| The native application has historically been approximately 10 MB&lt;br /&gt;
|-&lt;br /&gt;
| Open source&lt;br /&gt;
| ✅&lt;br /&gt;
| ✅&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
MemCP provides MySQL protocol compatibility but does not claim to implement every MySQL feature. See [[Comparison: MemCP vs. MySQL]] for a detailed comparison and [[Database Tools compatibility with MemCP]] for client compatibility.&lt;br /&gt;
&lt;br /&gt;
== Architecture overview ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tables, schemas and columns&#039;&#039;&#039;: Familiar SQL structures use a compressed columnar physical layout. See [[Databases, Tables and Columns]] and [[Columnar Storage]].&lt;br /&gt;
* &#039;&#039;&#039;Transaction model&#039;&#039;&#039;: Delta and main storage support mixed OLTP and OLAP semantics. See [[Transactions and Isolation]] and [[Shards, RecordIDs, Main Storage, Delta Storage]].&lt;br /&gt;
* &#039;&#039;&#039;Query planning&#039;&#039;&#039;: Logical optimization is separated from physical execution decisions. See [[Query Planner and Physical Lowering]].&lt;br /&gt;
* &#039;&#039;&#039;Persistence&#039;&#039;&#039;: Per-table durability can use filesystem, S3 or Ceph/RADOS storage. See [[Persistency and Performance Guarantees]] and [[Storage Backends]].&lt;br /&gt;
* &#039;&#039;&#039;Operations&#039;&#039;&#039;: The dashboard, metrics, process inspection and memory controls support day-to-day operation. See [[Dashboard and Operations]] and [[Memory Management and Eviction]].&lt;br /&gt;
* &#039;&#039;&#039;Scale-out roadmap&#039;&#039;&#039;: MemCP is single-node today. A leaderless CRUSH/RADOS and MOESI-inspired cluster design is planned, but must not be treated as an available production feature. See [[Cluster Monitor]].&lt;br /&gt;
* &#039;&#039;&#039;Frontends&#039;&#039;&#039;: MemCP provides multiple query and application interfaces:&lt;br /&gt;
** SQL through the MySQL wire protocol and SQL over HTTP;&lt;br /&gt;
** an RDF/graph query frontend;&lt;br /&gt;
** custom APIs through in-database web applications.&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
The following navigation remains on the start page so users and search engines can reach every major documentation area directly.&lt;br /&gt;
&lt;br /&gt;
=== Introduction and evaluation ===&lt;br /&gt;
&lt;br /&gt;
* [[What is OLTP and OLAP]]&lt;br /&gt;
* [[History of the MemCP project]]&lt;br /&gt;
* [[Hardware Requirements]]&lt;br /&gt;
* [[Persistency and Performance Guarantees]]&lt;br /&gt;
* [[Current Status and Open Issues]]&lt;br /&gt;
* [[MySQL is too slow|SQL performance problems MemCP solves]]&lt;br /&gt;
* [[Comparison: MemCP vs. MySQL]]&lt;br /&gt;
&lt;br /&gt;
=== Getting started ===&lt;br /&gt;
&lt;br /&gt;
* [[Install MemCP with Docker|Install with Docker]]&lt;br /&gt;
* [[With Singularity|Install with Singularity/Apptainer]]&lt;br /&gt;
* [[Compile MemCP from Source|Build from Source]]&lt;br /&gt;
* [[Contributing]]&lt;br /&gt;
* [[Introduction to Scheme]]&lt;br /&gt;
* [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
=== Administration ===&lt;br /&gt;
&lt;br /&gt;
* [[Deployment]]&lt;br /&gt;
* [[Migration from MySQL and PostgreSQL]]&lt;br /&gt;
* [[Settings]]&lt;br /&gt;
* [[Security and Authentication]]&lt;br /&gt;
* [[Dashboard and Operations]]&lt;br /&gt;
* [[Memory Management and Eviction]]&lt;br /&gt;
* [[Process Hibernation]]&lt;br /&gt;
* [[Performance Measurement]]&lt;br /&gt;
* [[MemCP Console]]&lt;br /&gt;
&lt;br /&gt;
=== Frontends ===&lt;br /&gt;
&lt;br /&gt;
==== SQL frontend ====&lt;br /&gt;
&lt;br /&gt;
* [[Supported SQL]]&lt;br /&gt;
* [[Advanced SQL Tutorial]]&lt;br /&gt;
* [[JSON|JSON and SQL/JSON]]&lt;br /&gt;
* [[Triggers]]&lt;br /&gt;
* [[SQL over REST]]&lt;br /&gt;
* [[Database Tools compatibility with MemCP|Supported Tooling]]&lt;br /&gt;
* [[Query Planner and Physical Lowering|How SQL operators are implemented]]&lt;br /&gt;
* [[Add custom SQL operators to MemCP]]&lt;br /&gt;
&lt;br /&gt;
==== RDF frontend ====&lt;br /&gt;
&lt;br /&gt;
* [[Introduction to RDF]]&lt;br /&gt;
* [[Advanced Graph Querying]]&lt;br /&gt;
* [https://github.com/launix-de/rdfop RDF browser and templating example]&lt;br /&gt;
&lt;br /&gt;
==== Custom frontends ====&lt;br /&gt;
&lt;br /&gt;
* [[In-Database WebApps and REST Services]]&lt;br /&gt;
* [[MemCP for Microservices]]&lt;br /&gt;
* [[Websockets in MemCP]]&lt;br /&gt;
&lt;br /&gt;
=== Persistence backends and storage ===&lt;br /&gt;
&lt;br /&gt;
* [[File System]]&lt;br /&gt;
* [[Storage Backends|S3-compatible and Ceph/RADOS storage]]&lt;br /&gt;
* [[Cluster Monitor]]&lt;br /&gt;
&lt;br /&gt;
=== Internals ===&lt;br /&gt;
&lt;br /&gt;
==== How MemCP works ====&lt;br /&gt;
&lt;br /&gt;
* [[Databases, Tables and Columns]]&lt;br /&gt;
* [[Shards, RecordIDs, Main Storage, Delta Storage]]&lt;br /&gt;
* [[Columnar Storage]]&lt;br /&gt;
* [[Transactions and Isolation]]&lt;br /&gt;
* [[Query Planner and Physical Lowering]]&lt;br /&gt;
* [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
==== Scheme documentation ====&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
&lt;br /&gt;
==== Optimizations ====&lt;br /&gt;
&lt;br /&gt;
* [[Benchmarks]]&lt;br /&gt;
* [[Query Planner and Physical Lowering]]&lt;br /&gt;
* [[In-Memory Compression, Columnar Compression Techniques]]&lt;br /&gt;
* [[Temporary Computed Columns]]&lt;br /&gt;
* [[Data Auto Sharding and Auto Indexing]]&lt;br /&gt;
* [[Parallel Computing]]&lt;br /&gt;
&lt;br /&gt;
== Further reading ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/launix-de/memcp MemCP on GitHub]&lt;br /&gt;
* [https://www.vldb.org/pvldb/vol13/p2649-boncz.pdf VLDB Research Paper]&lt;br /&gt;
* [https://cs.emis.de/LNI/Proceedings/Proceedings241/383.pdf LNI Proceedings Paper]&lt;br /&gt;
* [https://www.dcs.bbk.ac.uk/~dell/teaching/cc/paper/sigmod10/p135-malewicz.pdf Large Graph Algorithms]&lt;br /&gt;
&lt;br /&gt;
Additional blog posts on design decisions, compression techniques and performance optimization are available on the [https://launix.de/launix/ Launix blog].&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
&lt;br /&gt;
MemCP is an open-source project maintained by developers for developers. Contributions are welcome in the form of bug reports, feature requests and pull requests.&lt;br /&gt;
&lt;br /&gt;
See [[Contributing]] and the [https://github.com/launix-de/memcp GitHub repository].&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=RecSets&amp;diff=409</id>
		<title>RecSets</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=RecSets&amp;diff=409"/>
		<updated>2026-09-01T23:53:05Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 Carl-Philip Haensch --&amp;gt;&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: GPL-3.0-or-later --&amp;gt;&lt;br /&gt;
= RecSets: compact, parallel record-set processing =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&#039;&#039;&#039;Verified against commit &amp;lt;code&amp;gt;c42e19eba&amp;lt;/code&amp;gt; on 27 August 2026.&#039;&#039;&#039; RecSets are an internal physical execution mechanism. Applications normally use SQL and let the optimizer choose them.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;&#039;RecSet&#039;&#039;&#039; is a query-local subset of one MemCP table. Instead of materializing complete rows, it records the physical record IDs that currently qualify. The result remains table-shaped: &amp;lt;code&amp;gt;scan&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;scan_batch&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;scan_order&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;scan_order_multi&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;scan_exists&amp;lt;/code&amp;gt; can consume it as a source while retaining columnar reads, indexes, transaction visibility, and parallel shard execution.&lt;br /&gt;
&lt;br /&gt;
This separation is valuable on large relations. A cheap predicate can identify a narrow working set once; expensive residual predicates, correlated access checks, joins, projections, ordering, and aggregation then operate only on those candidates. Millions of base rows need not become millions of Scheme lists or wide temporary rows.&lt;br /&gt;
&lt;br /&gt;
== What a RecSet represents ==&lt;br /&gt;
&lt;br /&gt;
A RecSet contains membership, not result rows:&lt;br /&gt;
&lt;br /&gt;
* it belongs to exactly one base table and one transaction/visibility context;&lt;br /&gt;
* it has set semantics: no duplicates and no join multiplicity;&lt;br /&gt;
* it carries no result order;&lt;br /&gt;
* it is query-local and is neither persisted nor a stable public record-ID format;&lt;br /&gt;
* it can be an exact set of TRUE rows or a safe candidate superset followed by a residual predicate.&lt;br /&gt;
&lt;br /&gt;
The essential implementation is deliberately small:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
type recSet struct {&lt;br /&gt;
	table  *table&lt;br /&gt;
	shards []recSetShard&lt;br /&gt;
	count  int64&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
type recSetShard struct {&lt;br /&gt;
	shard    *storageShard&lt;br /&gt;
	kind     recSetRepresentation&lt;br /&gt;
	universe uint32&lt;br /&gt;
	data     []uint32&lt;br /&gt;
	used     uint32&lt;br /&gt;
	count    int64&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Each shard owns its own record-ID universe. This mirrors MemCP&#039;s storage layout and makes construction and set algebra naturally parallel without sharing a global bitmap or exposing record IDs across shards.&lt;br /&gt;
&lt;br /&gt;
== Adaptive representation ==&lt;br /&gt;
&lt;br /&gt;
One fixed representation would waste memory for either sparse or dense sets. Every RecSet shard therefore chooses among three forms:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Representation !! Layout !! Best fit !! Membership and combination&lt;br /&gt;
|-&lt;br /&gt;
| Ranges || Sorted &amp;lt;code&amp;gt;(base, count)&amp;lt;/code&amp;gt; pairs || Long runs, full/empty shards, or a nearly full set with a few holes || Range lookup; linear range sweeps&lt;br /&gt;
|-&lt;br /&gt;
| Positive IDs || Sorted, deduplicated &amp;lt;code&amp;gt;uint32&amp;lt;/code&amp;gt; record IDs || A small, scattered result || Sorted membership lookup; linear list merge/intersection&lt;br /&gt;
|-&lt;br /&gt;
| Bitmap || One bit per record-ID position || Dense or highly fragmented membership || Direct bit test and word-wise Boolean operations&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
There is intentionally no separate “full”, “empty”, or negative representation. An empty shard is zero ranges; a full shard is one range; “everything except a few holes” is a small number of ranges. A fragmented set eventually becomes a bitmap.&lt;br /&gt;
&lt;br /&gt;
For orientation, an uncompressed bitmap for a one-million-position shard needs approximately 125&amp;amp;nbsp;kB. A positive-ID result uses four bytes per hit before slice overhead, and a range uses eight bytes per run. The builder chooses according to the observed shape rather than a SQL selectivity guess. Immutable search-index RecSets have an additional compressed form: their positive IDs and ranges can themselves use MemCP&#039;s packed integer storage, and their small interface can intersect a mutable query-local RecSet in place.&lt;br /&gt;
&lt;br /&gt;
=== One-pass adaptive construction ===&lt;br /&gt;
&lt;br /&gt;
The builder starts with ranges. More than three isolated singleton runs indicate sparse, non-clustered data and trigger conversion to a positive list. If the compact representation exceeds the bitmap budget, it escalates to a bitmap.&lt;br /&gt;
&lt;br /&gt;
The filter predicate is evaluated &#039;&#039;&#039;exactly once per candidate record ID&#039;&#039;&#039;. A representation change copies already collected IDs or ranges; it never repeats the scan or replays Scheme predicates. This matters because a predicate may include decoded column values, JIT/interpreter work, search-index checks, or an expensive correlated condition. After construction, range and positive results are copied into right-sized slices so a small result does not keep the worst-case bitmap allocation alive.&lt;br /&gt;
&lt;br /&gt;
Ranges are also split at the immutable-main/delta boundary. Consumers can then bulk-read a main-storage run without accidentally spanning into transaction deltas.&lt;br /&gt;
&lt;br /&gt;
== Building a RecSet in the scan/filter path ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;scan_recset&amp;lt;/code&amp;gt; uses the normal MemCP scan machinery rather than walking every row blindly:&lt;br /&gt;
&lt;br /&gt;
# extract equality, range, LIKE/search, computed, and RecSet boundaries from the filter;&lt;br /&gt;
# order useful boundaries and derive index limits;&lt;br /&gt;
# schedule eligible shards in parallel;&lt;br /&gt;
# prepare only the columns named by the filter and optimize its Scheme procedure;&lt;br /&gt;
# read index candidates in batches of up to 1,024 record IDs;&lt;br /&gt;
# apply transaction/deletion visibility and the residual predicate once;&lt;br /&gt;
# feed qualifying IDs to the adaptive shard builder.&lt;br /&gt;
&lt;br /&gt;
This keeps late materialization intact. Creating &amp;lt;code&amp;gt;WHERE tenant_id = 7 AND state = &#039;open&#039;&amp;lt;/code&amp;gt; as a RecSet needs the filter columns, but it does not have to decode payload, JSON, or text columns that are only required by a later projection.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
(begin&lt;br /&gt;
	(define tx ((context &amp;quot;session&amp;quot;) &amp;quot;__memcp_tx&amp;quot;))&lt;br /&gt;
	(define orders (table &amp;quot;shop&amp;quot; &amp;quot;orders&amp;quot;))&lt;br /&gt;
	(define open_orders&lt;br /&gt;
		(scan_recset tx orders&lt;br /&gt;
			&#039;(&amp;quot;tenant_id&amp;quot; &amp;quot;state&amp;quot;)&lt;br /&gt;
			(lambda (tenant state)&lt;br /&gt;
				(and (equal? tenant 7) (equal? state &amp;quot;open&amp;quot;)))))&lt;br /&gt;
	(recset_count open_orders))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The low-level example illustrates the operator contract. SQL users should normally write the predicate in SQL and inspect the optimizer&#039;s decision with &amp;lt;code&amp;gt;EXPLAIN PHYSICAL&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== Narrowing an existing RecSet ===&lt;br /&gt;
&lt;br /&gt;
Passing a RecSet as the input of &amp;lt;code&amp;gt;scan_recset&amp;lt;/code&amp;gt; adds another condition without revisiting rows outside the existing membership:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
(define recent_open&lt;br /&gt;
	(scan_recset tx open_orders&lt;br /&gt;
		&#039;(&amp;quot;created_at&amp;quot;)&lt;br /&gt;
		(lambda (created_at) (&amp;gt;= created_at cutoff))))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For a very sparse input, MemCP walks its IDs directly. For a broader input, it combines the exact RecSet boundary with other index/search boundaries before reading residual columns. This is the intended pattern for “cheap selective predicate first, expensive predicate second”, including ACL or search conditions with their own subscans.&lt;br /&gt;
&lt;br /&gt;
When scanning a RecSet, consecutive visible main-storage IDs are coalesced into runs. Each required column is fetched for the whole run with &amp;lt;code&amp;gt;GetValueRange&amp;lt;/code&amp;gt;; visibility remains row-specific, while column decoding becomes batched and cache-friendly. Delta rows use their transaction-aware delta path.&lt;br /&gt;
&lt;br /&gt;
== Membership inside another scan ==&lt;br /&gt;
&lt;br /&gt;
The pseudo-column &amp;lt;code&amp;gt;$recset_contains&amp;lt;/code&amp;gt; supplies a closure bound to the current row. It tests one or more same-table RecSets without exposing physical record IDs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
(scan tx orders&lt;br /&gt;
	&#039;(&amp;quot;$recset_contains&amp;quot; &amp;quot;total&amp;quot;)&lt;br /&gt;
	(lambda (contains total)&lt;br /&gt;
		(and (contains open_orders) (&amp;gt; total 1000)))&lt;br /&gt;
	&#039;(&amp;quot;id&amp;quot;)&lt;br /&gt;
	(lambda (id) id)&lt;br /&gt;
	(lambda (sum id) (+ sum id))&lt;br /&gt;
	0)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The closure caches the current RecSet and its shard entry, avoiding a repeated shard search for successive membership calls. If an exact RecSet boundary already proves the membership condition, the scan can provide an always-true closure instead of probing it again. Multiple &amp;lt;code&amp;gt;$recset_contains&amp;lt;/code&amp;gt; parameters are supported when a filter needs independent sets.&lt;br /&gt;
&lt;br /&gt;
== Set algebra, in parallel ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
(define visible (recset_intersect (list tenant_rows active_rows)))&lt;br /&gt;
(define either  (recset_union (list starred_rows recent_rows)))&lt;br /&gt;
(define allowed (recset_difference (list visible blocked_rows muted_rows)))&lt;br /&gt;
(define other_visible_rows (recset_not visible))&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Union, intersection, and difference require operands from the same table. Sorted range/list invariants allow linear two-pointer or N-way sweeps; bitmap pairs use word operations. Mixed representation pairs have specialized implementations instead of expanding everything into one common row list.&lt;br /&gt;
&lt;br /&gt;
Each shard combination is independent and runs through MemCP&#039;s bounded fan-out scheduler. Results are sorted back into deterministic shard order after parallel completion. This lets Boolean work over millions of record positions use available cores while keeping synchronization out of the inner membership loop.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;recset_not&amp;lt;/code&amp;gt; deserves special attention: it constructs the currently visible table universe and subtracts the input. It does not merely invert raw bits, because that could resurrect deleted rows or rows invisible to the transaction. At SQL level, a RecSet complement is also not automatically equivalent to &amp;lt;code&amp;gt;NOT predicate&amp;lt;/code&amp;gt; when NULL/UNKNOWN is possible.&lt;br /&gt;
&lt;br /&gt;
== Projecting membership through a join ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;recset_project_join&amp;lt;/code&amp;gt; reads distinct source keys from one RecSet and creates a RecSet over matching rows of another table. This is useful for EXISTS/IN carriers, ACL links, tags, and search-result relations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
(define permitted_links&lt;br /&gt;
	(scan_recset tx access_links&lt;br /&gt;
		&#039;(&amp;quot;user_id&amp;quot;)&lt;br /&gt;
		(lambda (user_id) (equal? user_id current_user))))&lt;br /&gt;
&lt;br /&gt;
(define permitted_documents&lt;br /&gt;
	(recset_project_join tx permitted_links&lt;br /&gt;
		&#039;(&amp;quot;document_id&amp;quot;) documents &#039;(&amp;quot;id&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
(scan_order tx permitted_documents&lt;br /&gt;
	&#039;() (lambda () true)&lt;br /&gt;
	&#039;(&amp;quot;created_at&amp;quot; &amp;quot;id&amp;quot;) &#039;(&amp;lt; &amp;lt;)&lt;br /&gt;
	0 0 50&lt;br /&gt;
	&#039;(&amp;quot;id&amp;quot; &amp;quot;title&amp;quot;)&lt;br /&gt;
	(lambda (id title) (list id title))&lt;br /&gt;
	(lambda (rows row) (append rows (list row)))&lt;br /&gt;
	&#039;() false)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Composite source/target keys are supported. At execution time the operator knows the actual number of distinct source keys and target rows per shard. It chooses between indexed point probes and a dense target scan. A single integral key can use an O(1) hash membership test during the dense scan; generic composite keys use sorted tuples and binary lookup.&lt;br /&gt;
&lt;br /&gt;
The current cost constants were calibrated with production-shaped A/B fixtures. One recorded case projected about 80,000 integral keys through 1.84 million target rows in roughly 8&amp;amp;nbsp;ms on the calibration machine, while another case with 105 keys and 22 indexed target shards favored point probes. These are decision-model observations, &#039;&#039;&#039;not portable latency guarantees&#039;&#039;&#039;; hardware, encodings, shard layout, visibility state, and surrounding query work matter.&lt;br /&gt;
&lt;br /&gt;
For repeated scalar membership checks, &amp;lt;code&amp;gt;recset_key_index&amp;lt;/code&amp;gt; builds an immutable lookup closure over one or more columns:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
(define contains_document&lt;br /&gt;
	(recset_key_index tx permitted_documents &#039;(&amp;quot;id&amp;quot;)))&lt;br /&gt;
&lt;br /&gt;
(contains_document 12345)&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Ordering, LIMIT, and adaptive batches ==&lt;br /&gt;
&lt;br /&gt;
A RecSet itself is unordered. &amp;lt;code&amp;gt;scan_order&amp;lt;/code&amp;gt; applies an index/order from the base table and intersects it with RecSet membership. Depending on cardinality, index span, and LIMIT, the execution kernel can:&lt;br /&gt;
&lt;br /&gt;
* drive the base ordered index and test RecSet membership;&lt;br /&gt;
* translate sparse RecSet IDs into ordered index positions and sort those positions;&lt;br /&gt;
* iterate the RecSet directly when no useful ordering is required.&lt;br /&gt;
&lt;br /&gt;
The crossover is calibrated by a benchmark with 800,000 rows, RecSet cardinalities from 16 to 720,000, bounded and unbounded scans, and both distributed and adversarial late hits. &amp;lt;code&amp;gt;EXPLAIN PHYSICAL&amp;lt;/code&amp;gt; can report the adaptive RecSet boundary and runtime alternatives such as &amp;lt;code&amp;gt;ordered_inverse_recset&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ordered_base_membership&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For an ORDER BY/LIMIT query whose expensive acceptance condition lives on another relation, &amp;lt;code&amp;gt;scan_order_batch_accept&amp;lt;/code&amp;gt; preserves order without evaluating the whole candidate domain. It draws an initial ordered RecSet of &amp;lt;code&amp;gt;OFFSET + LIMIT&amp;lt;/code&amp;gt; candidates, asks a batch function to return an exact accepted subset, and doubles subsequent disjoint batches until enough rows are accepted or the source is exhausted. The accepted RecSet is used as a mask against the already ordered vector, so it is not rescanned in physical-ID order.&lt;br /&gt;
&lt;br /&gt;
This is especially useful for ordered document/search/ACL queries: project a candidate batch to the access relation, filter it in parallel, project accepted membership back, and stop once the requested page is complete.&lt;br /&gt;
&lt;br /&gt;
== How the optimizer uses RecSets ==&lt;br /&gt;
&lt;br /&gt;
RecSets appear only during physical lowering. The logical planner first establishes joins, domains, SQL truth semantics, grouping, ordering, and multiplicity. The physical cost model can then compare:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Choice !! Often attractive when&lt;br /&gt;
|-&lt;br /&gt;
| Direct indexed probe || The driving side is small and each lookup is selective.&lt;br /&gt;
|-&lt;br /&gt;
| RecSet carrier || A filtered domain is reused, projected, combined, or much narrower than the base relation.&lt;br /&gt;
|-&lt;br /&gt;
| Prepared key/group table || Keys or aggregate results need relational reuse and more than membership.&lt;br /&gt;
|-&lt;br /&gt;
| Dense fused scan || Most rows are visited once and building a reusable carrier would add work.&lt;br /&gt;
|-&lt;br /&gt;
| Ordered RecSet iterator || An existing membership domain must be consumed in base-table order or with a small LIMIT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Candidate RecSets do not permit the optimizer to drop correctness checks. Approximate LIKE/full-text boundaries and other safe supersets retain their residual SQL predicate. Nullable &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;NOT IN&amp;lt;/code&amp;gt; and general three-valued logic are handled before truth-only Boolean set identities are applied.&lt;br /&gt;
&lt;br /&gt;
Use these views when investigating a plan:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
EXPLAIN IR SELECT ...;&lt;br /&gt;
EXPLAIN REORDER SELECT ...;&lt;br /&gt;
EXPLAIN PHYSICAL SELECT ...;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;EXPLAIN PHYSICAL&amp;lt;/code&amp;gt; exposes membership-carrier choices and runtime access alternatives for projected and ordered RecSets. A remaining roadmap item is richer tracing for why the same RecSet domain was built or reused and for the exact ordered-iterator mode chosen at runtime.&lt;br /&gt;
&lt;br /&gt;
== Operational and correctness limits ==&lt;br /&gt;
&lt;br /&gt;
* Do not retain a RecSet as application state or persist its physical IDs.&lt;br /&gt;
* Algebra operands must refer to the same table; projected joins deliberately return a new target-table RecSet.&lt;br /&gt;
* A RecSet is tied to its transaction/visibility context. Batch-accept callbacks must return a same-table, same-transaction subset.&lt;br /&gt;
* Scanning a RecSet for reads is supported; mutation callbacks such as &amp;lt;code&amp;gt;$update&amp;lt;/code&amp;gt; are rejected on a RecSet source.&lt;br /&gt;
* Cancellation is checked before shard work is scheduled. Once entered, one shard&#039;s RecSet build runs atomically.&lt;br /&gt;
* Set cardinality is not SQL row cardinality after a one-to-many join, and membership does not retain duplicate keys.&lt;br /&gt;
* Ordered output needs &amp;lt;code&amp;gt;scan_order&amp;lt;/code&amp;gt;; include a unique tie-breaker when stable pagination matters.&lt;br /&gt;
&lt;br /&gt;
== Low-level operator map ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Operator !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;scan_recset&amp;lt;/code&amp;gt; || Build from a table or narrow an existing RecSet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;recset_count&amp;lt;/code&amp;gt; || Return stored membership cardinality.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;recset_union&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;recset_intersect&amp;lt;/code&amp;gt; || Combine same-table memberships.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;recset_difference&amp;lt;/code&amp;gt; / &amp;lt;code&amp;gt;recset_not&amp;lt;/code&amp;gt; || Subtract sets or complement against visible rows.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;recset_project_join&amp;lt;/code&amp;gt; || Project distinct keys into a target-table RecSet.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;recset_key_index&amp;lt;/code&amp;gt; || Build an immutable scalar/composite-key membership closure.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;$recset_contains&amp;lt;/code&amp;gt; || Test current-row membership inside a scan predicate.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;scan_order_batch_accept&amp;lt;/code&amp;gt; || Filter progressively larger ordered candidate RecSets before LIMIT.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The generated [[Storage]] reference is authoritative for exact signatures. For the surrounding execution architecture see [[Scan]], [[Query Planner and Physical Lowering]], [[Columnar Storage]], [[Data Auto Sharding and Auto Indexing]], and [[Parallel Computing]].&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Supported_SQL&amp;diff=371</id>
		<title>Supported SQL</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Supported_SQL&amp;diff=371"/>
		<updated>2026-08-28T10:03:52Z</updated>

		<summary type="html">&lt;p&gt;Carli: /* Planner inspection */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!-- Copyright (C) 2026 Carl-Philip Haensch --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!-- SPDX-License-Identifier: GPL-3.0-or-later --&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;supported-sql&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Supported SQL =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;Verified against development commit &amp;lt;code&amp;gt;c42e19eba&amp;lt;/code&amp;gt; on 27 August 2026. MemCP is Beta and does not claim complete MySQL or PostgreSQL compatibility. Unsupported shapes should fail explicitly; test a required workload before migration.&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
This page is a capability map for application evaluation. MemCP accepts a broad MySQL-oriented dialect through its MySQL protocol and HTTP endpoint, plus PostgreSQL-oriented syntax through a separate HTTP endpoint. Both compile into the same logical planner and storage runtime, but accepted surface syntax and returned metadata can differ by frontend.&lt;br /&gt;
&lt;br /&gt;
Support is defined by tested semantics, not merely by whether the parser accepts a statement. Compatibility-only clauses may intentionally be no-ops, and uncommon combinations can remain unsupported even when their individual operators are available. Use this overview to select candidates, then verify every required query, constraint, transaction, prepared statement, and client behavior against the deployed release.&lt;br /&gt;
&amp;lt;span id=&amp;quot;query-language&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Query language ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;SELECT&amp;lt;/code&amp;gt;, aliases, &amp;lt;code&amp;gt;WHERE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DISTINCT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GROUP BY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;HAVING&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ORDER BY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LIMIT&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;OFFSET&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;INNER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LEFT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RIGHT&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;CROSS JOIN&amp;lt;/code&amp;gt;;&lt;br /&gt;
* &amp;lt;code&amp;gt;UNION&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UNION ALL&amp;lt;/code&amp;gt;, including ordered/limited set results;&lt;br /&gt;
* derived tables and logical SQL views;&lt;br /&gt;
* scalar, &amp;lt;code&amp;gt;EXISTS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;NOT EXISTS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;NOT IN&amp;lt;/code&amp;gt; subqueries, including many correlated and grouped forms;&lt;br /&gt;
* aggregates &amp;lt;code&amp;gt;COUNT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;SUM&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;AVG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MIN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MAX&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;GROUP_CONCAT&amp;lt;/code&amp;gt;;&lt;br /&gt;
* window functions including &amp;lt;code&amp;gt;ROW_NUMBER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RANK&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;DENSE_RANK&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LEAD&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;LAG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;FIRST_VALUE&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;LAST_VALUE&amp;lt;/code&amp;gt; with partition/order clauses.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;data-modification-and-schema&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Data modification and schema ==&lt;br /&gt;
&lt;br /&gt;
* single- and multi-row &amp;lt;code&amp;gt;INSERT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;INSERT IGNORE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;INSERT … SELECT&amp;lt;/code&amp;gt;, and MySQL or PostgreSQL upsert syntax;&lt;br /&gt;
* &amp;lt;code&amp;gt;UPDATE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;DELETE&amp;lt;/code&amp;gt;, including qualified and supported multi-table forms;&lt;br /&gt;
* &amp;lt;code&amp;gt;CREATE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;ALTER&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;RENAME&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;TRUNCATE&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;DROP&amp;lt;/code&amp;gt; for databases and tables;&lt;br /&gt;
* &amp;lt;code&amp;gt;CREATE VIEW&amp;lt;/code&amp;gt;, indexes, primary/unique keys, foreign keys, defaults, &amp;lt;code&amp;gt;AUTO_INCREMENT&amp;lt;/code&amp;gt;, computed expressions, types, collations, and per-table ENGINE;&lt;br /&gt;
* persistent BEFORE/AFTER triggers for INSERT, UPDATE, and DELETE.&lt;br /&gt;
&lt;br /&gt;
Foreign keys are enforced for the tested RESTRICT, CASCADE, and SET NULL paths. Some compatibility DDL is intentionally accepted as a no-op; for example, a client accepting &amp;lt;code&amp;gt;ADD FULLTEXT&amp;lt;/code&amp;gt; does not imply a MySQL-compatible full-text index implementation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;transactions-security-and-metadata&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Transactions, security, and metadata ==&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;code&amp;gt;BEGIN&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;COMMIT&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;ROLLBACK&amp;lt;/code&amp;gt;;&lt;br /&gt;
* users, passwords, grants, revokes, and database access policies;&lt;br /&gt;
* &amp;lt;code&amp;gt;SHOW DATABASES&amp;lt;/code&amp;gt;, tables, columns, indexes, create-table metadata, variables, engines, processlist, and selected &amp;lt;code&amp;gt;INFORMATION_SCHEMA&amp;lt;/code&amp;gt; relations;&lt;br /&gt;
* prepared statements over the MySQL protocol;&lt;br /&gt;
* &amp;lt;code&amp;gt;KILL QUERY&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;KILL CONNECTION&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
See [[Transactions_and_Isolation|Transactions and Isolation]] and [[Security_and_Authentication|Security and Authentication]] for the operational contract.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;expressions&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Expressions ==&lt;br /&gt;
&lt;br /&gt;
MemCP implements SQL NULL/three-valued logic, CASE, COALESCE/NULLIF/IFNULL, arithmetic and bitwise operators, comparisons, BETWEEN, IN lists, LIKE/ILIKE, REGEXP/RLIKE, MATCH…AGAINST compatibility, casts, string functions, mathematical functions, hashes, date/time functions, intervals, and timezone conversion.&lt;br /&gt;
&lt;br /&gt;
The exact parser and function catalog changes more often than this overview. Use the generated API reference and the SQL test taxonomy for detailed coverage.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;json&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== JSON ==&lt;br /&gt;
&lt;br /&gt;
MemCP stores declared &amp;lt;code&amp;gt;JSON&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;JSONB&amp;lt;/code&amp;gt; values in a native tagged BSON representation. The MySQL dialect implements JSON validation, type inspection, path extraction, constructors, aggregates, mutation functions, containment/search operations, &amp;lt;code&amp;gt;JSON_TABLE&amp;lt;/code&amp;gt;, and the &amp;lt;code&amp;gt;-&amp;gt;&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;-&amp;gt;&amp;gt;&amp;lt;/code&amp;gt; operators. The PostgreSQL dialect provides its corresponding &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;jsonb&amp;lt;/code&amp;gt; operators, constructors, aggregates, path functions, and set-returning expansion forms. Deterministic path expressions can be materialized and indexed through the ordinary computed-column/index machinery. See [[JSON]] for the detailed compatibility contract and deviations.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;planner-inspection&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Planner inspection ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;EXPLAIN SELECT ...;&lt;br /&gt;
EXPLAIN IR SELECT ...;&lt;br /&gt;
EXPLAIN REORDER SELECT ...;&lt;br /&gt;
EXPLAIN PHYSICAL SELECT ...;&lt;br /&gt;
EXPLAIN COMPILE SELECT ...;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See [[Query Planner and Physical Lowering]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;known-limitations&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== Known limitations ==&lt;br /&gt;
&lt;br /&gt;
MemCP is not a byte-for-byte MySQL server implementation. Metadata details, administrative commands, uncommon syntax, advanced locking modes, XA, stored procedures, and untested SQL-standard edge cases may be absent. Consult the [https://github.com/launix-de/memcp/issues current issue tracker] and add a must-pass and must-fail test for every application-critical construct.&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Main_Page&amp;diff=298</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Main_Page&amp;diff=298"/>
		<updated>2026-08-27T06:47:12Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= MemCP – A Modern In-Memory Columnar Database =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:2.5rem 2rem; margin:0 0 1.5rem; border-radius:14px; background:linear-gradient(135deg,#3d6208 0%,#64910c 52%,#76b512 100%); color:#fff; text-align:center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:2.6rem; line-height:1.1; font-weight:700; margin-bottom:.7rem;&amp;quot;&amp;gt;MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.45rem; line-height:1.35; font-weight:600; margin:0 auto .9rem; max-width:56rem;&amp;quot;&amp;gt;A fast, compressed, MySQL-compatible columnar database for modern OLTP and OLAP workloads&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.05rem; line-height:1.6; margin:0 auto 1.4rem; max-width:54rem;&amp;quot;&amp;gt;MemCP combines persistent in-memory operation, adaptive column compression, parallel query execution and direct application APIs in a lightweight database written in Go.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-bottom:1.5rem;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;Beta&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;Open Source&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;MySQL Protocol + HTTP APIs&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;plainlinks&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[[Install MemCP with Docker|&amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border-radius:6px; background:#fff; color:#496f0c; font-weight:700;&amp;quot;&amp;gt;Get started with Docker&amp;lt;/span&amp;gt;]]&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[[Supported SQL|&amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border:1px solid #fff; border-radius:6px; color:#fff; font-weight:700;&amp;quot;&amp;gt;Explore SQL support&amp;lt;/span&amp;gt;]]&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[https://github.com/launix-de/memcp &amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border:1px solid #fff; border-radius:6px; color:#fff; font-weight:700;&amp;quot;&amp;gt;View on GitHub&amp;lt;/span&amp;gt;]&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Memcp-Load.png|center|frameless|1000px|alt=MemCP database dashboard and workload overview]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.85rem 1rem; margin:1rem 0 2rem; border-left:5px solid #d99b00; background:#fff7d6; color:#332600;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Development status: Beta.&#039;&#039;&#039; MemCP is under active development. Check [[Supported SQL]], [[Current Status and Open Issues]] and the durability requirements of your workload before migrating production data.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Choose your path ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:1rem; margin:1rem 0 2rem;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Evaluate MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
Understand the workload model, current status, hardware needs and differences from MySQL.&lt;br /&gt;
&lt;br /&gt;
[[What is OLTP and OLAP|OLTP and OLAP]] · [[Comparison: MemCP vs. MySQL|Compare with MySQL]] · [[Hardware Requirements|Hardware requirements]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Build an application&amp;lt;/div&amp;gt;&lt;br /&gt;
Use the MySQL protocol, SQL over HTTP, RDF or application-specific endpoints inside MemCP.&lt;br /&gt;
&lt;br /&gt;
[[Advanced SQL Tutorial|SQL tutorial]] · [[SQL over REST|SQL over HTTP]] · [[Database Tools compatibility with MemCP|Client tooling]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Operate MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
Plan deployment, migration, persistence, storage backends, settings and performance measurement.&lt;br /&gt;
&lt;br /&gt;
[[Deployment]] · [[Persistency and Performance Guarantees|Durability]] · [[Migration from MySQL and PostgreSQL|Migration]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Understand and contribute&amp;lt;/div&amp;gt;&lt;br /&gt;
Explore the storage engine, optimizer, embedded Scheme runtime and project internals.&lt;br /&gt;
&lt;br /&gt;
[[Query Planner and Physical Lowering|Query planner]] · [[Columnar Storage]] · [[Contributing]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
=== Run with Docker ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run --name memcp \&lt;br /&gt;
  -e ROOT_PASSWORD=&#039;choose-a-password&#039; \&lt;br /&gt;
  -p 4321:4321 -p 3307:3307 \&lt;br /&gt;
  carli2/memcp:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then open &amp;lt;code&amp;gt;http://localhost:4321&amp;lt;/code&amp;gt; and connect a MySQL application to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on port &#039;&#039;&#039;3307&#039;&#039;&#039;. Add a volume mounted at &amp;lt;code&amp;gt;/data&amp;lt;/code&amp;gt; when the container must retain persistent data. See [[Install MemCP with Docker|the complete Docker guide]] before deploying it as a service.&lt;br /&gt;
&lt;br /&gt;
=== Build from source ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://github.com/launix-de/memcp&lt;br /&gt;
cd memcp&lt;br /&gt;
go mod download&lt;br /&gt;
make&lt;br /&gt;
./memcp --api-port=4321 --mysql-port=3307 lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connect with MySQL tooling:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 127.0.0.1 -u root -p -P 3307&lt;br /&gt;
# Enter the password selected for this data directory.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The development default for a fresh data directory is &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt;. Change it before exposing MemCP to another machine. MemCP can also be supervised with PM2:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pm2 start ./memcp --name memcp -- \&lt;br /&gt;
  --no-repl -data ./data --api-port=4321 --mysql-port=3307 lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Background deployments must use &amp;lt;code&amp;gt;--no-repl&amp;lt;/code&amp;gt; so that closing standard input does not terminate the interactive console and stop the server. See [[Compile MemCP from Source|Build from Source]], [[Deployment]] and [[MemCP Console]].&lt;br /&gt;
&lt;br /&gt;
== Key features ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:.8rem; margin:1rem 0;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;High performance&#039;&#039;&#039;&amp;lt;br /&amp;gt;NUMA-aware, parallelized query execution is optimized for multicore CPUs, large caches and NVMe SSDs, serving both OLTP and OLAP workloads.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Columnar storage&#039;&#039;&#039;&amp;lt;br /&amp;gt;Data is stored by column for improved compression, a smaller memory footprint and fast analytical access.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Persistent in-memory operation&#039;&#039;&#039;&amp;lt;br /&amp;gt;MemCP is designed to keep active data in memory while offering configurable per-table durability and persistence backends.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Built-in APIs&#039;&#039;&#039;&amp;lt;br /&amp;gt;SQL over HTTP and in-database services can remove an extra middleware hop for suitable applications.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Adaptive compression&#039;&#039;&#039;&amp;lt;br /&amp;gt;Bit-packing, dictionary encoding and sequence compression can reduce suitable datasets by up to 80% compared with their MySQL/MariaDB representation.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Simple deployment&#039;&#039;&#039;&amp;lt;br /&amp;gt;Start with Docker, PM2 or the native binary. The compact application has historically had an installation footprint of approximately 10 MB.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Extensible frontends&#039;&#039;&#039;&amp;lt;br /&amp;gt;The Go storage engine and embedded Scheme environment support SQL, RDF, REST and custom application interfaces.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #9ad32d; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Cost-based query execution&#039;&#039;&#039;&amp;lt;br /&amp;gt;Logical decorrelation and join optimization are separated from cost-based physical selection of scans, indexes, RecSets, reusable caches and execution pipelines.&amp;lt;br /&amp;gt;[[Query Planner and Physical Lowering|How MemCP plans and lowers queries →]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why MemCP? ==&lt;br /&gt;
&lt;br /&gt;
Traditional relational databases were designed around spinning disks and comparatively small numbers of CPU cores. MemCP rethinks storage and query execution for modern multicore systems, large caches, fast storage and mixed workloads.&lt;br /&gt;
&lt;br /&gt;
Typical use cases include:&lt;br /&gt;
&lt;br /&gt;
* real-time dashboards and analytics;&lt;br /&gt;
* data-heavy SaaS platforms;&lt;br /&gt;
* embedded systems with limited resources;&lt;br /&gt;
* high-throughput OLTP/OLAP hybrids.&lt;br /&gt;
&lt;br /&gt;
Whether MemCP is a good fit depends on the required SQL compatibility, durability, query mix, data size and operational environment. Review [[Supported SQL]], [[Persistency and Performance Guarantees]] and [[Performance Measurement]] rather than treating benchmark figures as universal guarantees.&lt;br /&gt;
&lt;br /&gt;
== MemCP vs. MySQL ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
! Feature&lt;br /&gt;
! MySQL&lt;br /&gt;
! MemCP&lt;br /&gt;
|-&lt;br /&gt;
| Storage model&lt;br /&gt;
| Primarily row-based&lt;br /&gt;
| Column-based and compressed&lt;br /&gt;
|-&lt;br /&gt;
| Performance focus&lt;br /&gt;
| General-purpose relational workloads&lt;br /&gt;
| NUMA-aware, in-memory execution for mixed operational and analytical workloads&lt;br /&gt;
|-&lt;br /&gt;
| In-memory capability&lt;br /&gt;
| Available through selected engines and caching&lt;br /&gt;
| Central design goal and default operating model&lt;br /&gt;
|-&lt;br /&gt;
| REST API integration&lt;br /&gt;
| Normally external&lt;br /&gt;
| Built in&lt;br /&gt;
|-&lt;br /&gt;
| Installation footprint&lt;br /&gt;
| Common server installations are approximately 150 MB or larger&lt;br /&gt;
| The native application has historically been approximately 10 MB&lt;br /&gt;
|-&lt;br /&gt;
| Open source&lt;br /&gt;
| ✅&lt;br /&gt;
| ✅&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
MemCP provides MySQL protocol compatibility but does not claim to implement every MySQL feature. See [[Comparison: MemCP vs. MySQL]] for a detailed comparison and [[Database Tools compatibility with MemCP]] for client compatibility.&lt;br /&gt;
&lt;br /&gt;
== Architecture overview ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tables, schemas and columns&#039;&#039;&#039;: Familiar SQL structures use a compressed columnar physical layout. See [[Databases, Tables and Columns]] and [[Columnar Storage]].&lt;br /&gt;
* &#039;&#039;&#039;Transaction model&#039;&#039;&#039;: Delta and main storage support mixed OLTP and OLAP semantics. See [[Transactions and Isolation]] and [[Shards, RecordIDs, Main Storage, Delta Storage]].&lt;br /&gt;
* &#039;&#039;&#039;Query planning&#039;&#039;&#039;: Logical optimization is separated from physical execution decisions. See [[Query Planner and Physical Lowering]].&lt;br /&gt;
* &#039;&#039;&#039;Persistence&#039;&#039;&#039;: Per-table durability can use filesystem, S3 or Ceph/RADOS storage. See [[Persistency and Performance Guarantees]].&lt;br /&gt;
* &#039;&#039;&#039;Frontends&#039;&#039;&#039;: MemCP provides multiple query and application interfaces:&lt;br /&gt;
** SQL through the MySQL wire protocol and SQL over HTTP;&lt;br /&gt;
** an RDF/graph query frontend;&lt;br /&gt;
** custom APIs through in-database web applications.&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
The following navigation remains on the start page so users and search engines can reach every major documentation area directly.&lt;br /&gt;
&lt;br /&gt;
=== Introduction and evaluation ===&lt;br /&gt;
&lt;br /&gt;
* [[What is OLTP and OLAP]]&lt;br /&gt;
* [[History of the MemCP project]]&lt;br /&gt;
* [[Hardware Requirements]]&lt;br /&gt;
* [[Persistency and Performance Guarantees]]&lt;br /&gt;
* [[Current Status and Open Issues]]&lt;br /&gt;
* [[Comparison: MemCP vs. MySQL]]&lt;br /&gt;
&lt;br /&gt;
=== Getting started ===&lt;br /&gt;
&lt;br /&gt;
* [[Install MemCP with Docker|Install with Docker]]&lt;br /&gt;
* [[With Singularity|Install with Singularity/Apptainer]]&lt;br /&gt;
* [[Compile MemCP from Source|Build from Source]]&lt;br /&gt;
* [[Contributing]]&lt;br /&gt;
* [[Introduction to Scheme]]&lt;br /&gt;
* [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
=== Administration ===&lt;br /&gt;
&lt;br /&gt;
* [[Deployment]]&lt;br /&gt;
* [[Migration from MySQL and PostgreSQL]]&lt;br /&gt;
* [[Settings]]&lt;br /&gt;
* [[Process Hibernation]]&lt;br /&gt;
* [[Performance Measurement]]&lt;br /&gt;
* [[MemCP Console]]&lt;br /&gt;
&lt;br /&gt;
=== Frontends ===&lt;br /&gt;
&lt;br /&gt;
==== SQL frontend ====&lt;br /&gt;
&lt;br /&gt;
* [[Supported SQL]]&lt;br /&gt;
* [[Advanced SQL Tutorial]]&lt;br /&gt;
* [[SQL over REST]]&lt;br /&gt;
* [[Database Tools compatibility with MemCP|Supported Tooling]]&lt;br /&gt;
* [[How SQL Operators are implemented on MemCP]]&lt;br /&gt;
* [[Add custom SQL operators to MemCP]]&lt;br /&gt;
&lt;br /&gt;
==== RDF frontend ====&lt;br /&gt;
&lt;br /&gt;
* [[Introduction to RDF]]&lt;br /&gt;
* [[Advanced Graph Querying]]&lt;br /&gt;
* [[RDF templating and model driven development]]&lt;br /&gt;
&lt;br /&gt;
==== Custom frontends ====&lt;br /&gt;
&lt;br /&gt;
* [[In-Database WebApps|In-Database WebApps and REST Services]]&lt;br /&gt;
* [[MemCP for Microservices]]&lt;br /&gt;
* [[Websockets in MemCP]]&lt;br /&gt;
&lt;br /&gt;
=== Persistence backends and storage ===&lt;br /&gt;
&lt;br /&gt;
* [[File System]]&lt;br /&gt;
* [[S3 Buckets]]&lt;br /&gt;
* [[Ceph/Rados]]&lt;br /&gt;
* [[Cluster Monitor]]&lt;br /&gt;
&lt;br /&gt;
=== Internals ===&lt;br /&gt;
&lt;br /&gt;
==== How MemCP works ====&lt;br /&gt;
&lt;br /&gt;
* [[Databases, Tables and Columns]]&lt;br /&gt;
* [[Shards, RecordIDs, Main Storage, Delta Storage]]&lt;br /&gt;
* [[Columnar Storage]]&lt;br /&gt;
* [[Transactions and Isolation]]&lt;br /&gt;
* [[Query Planner and Physical Lowering]]&lt;br /&gt;
* [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
==== Scheme documentation ====&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Window Functions]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Timezone]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
* [[Transactions]]&lt;br /&gt;
* [[JIT in Scheme|JIT]]&lt;br /&gt;
&lt;br /&gt;
==== Optimizations ====&lt;br /&gt;
&lt;br /&gt;
* [[Query Planner and Physical Lowering]]&lt;br /&gt;
* [[In-Memory Compression, Columnar Compression Techniques]]&lt;br /&gt;
* [[Temporary Columns]]&lt;br /&gt;
* [[Data Auto Sharding and Auto Indexing]]&lt;br /&gt;
* [[Parallel Computing]]&lt;br /&gt;
&lt;br /&gt;
== Further reading ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/launix-de/memcp MemCP on GitHub]&lt;br /&gt;
* [https://www.vldb.org/pvldb/vol13/p2649-boncz.pdf VLDB Research Paper]&lt;br /&gt;
* [https://cs.emis.de/LNI/Proceedings/Proceedings241/383.pdf LNI Proceedings Paper]&lt;br /&gt;
* [https://www.dcs.bbk.ac.uk/~dell/teaching/cc/paper/sigmod10/p135-malewicz.pdf Large Graph Algorithms]&lt;br /&gt;
&lt;br /&gt;
Additional blog posts on design decisions, compression techniques and performance optimization are available on the [https://launix.de/launix/ Launix blog].&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
&lt;br /&gt;
MemCP is an open-source project maintained by developers for developers. Contributions are welcome in the form of bug reports, feature requests and pull requests.&lt;br /&gt;
&lt;br /&gt;
See [[Contributing]] and the [https://github.com/launix-de/memcp GitHub repository].&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Window_Functions&amp;diff=297</id>
		<title>Window Functions</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Window_Functions&amp;diff=297"/>
		<updated>2026-08-27T06:38:43Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot;← Back to Full SCM API documentation  == stream_emit ==  invokes a streaming callback immediately; marks ordering-sensitive emission as an observable effect  &amp;#039;&amp;#039;&amp;#039;Allowed number of parameters:&amp;#039;&amp;#039;&amp;#039; 2–2  &amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; === Parameters ===  * &amp;#039;&amp;#039;&amp;#039;emit&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;func(value:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): * &amp;#039;&amp;#039;&amp;#039;value&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;):  &amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; === Returns ===  &amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;  == stream_window_reduce ==  applies OFFSET/LIMIT and a serial redu...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
== stream_emit ==&lt;br /&gt;
&lt;br /&gt;
invokes a streaming callback immediately; marks ordering-sensitive emission as an observable effect&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;emit&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(value:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== stream_window_reduce ==&lt;br /&gt;
&lt;br /&gt;
applies OFFSET/LIMIT and a serial reducer to complete values emitted by a nested streaming producer without collecting an intermediate relation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 5–5&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;offset&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of complete producer values to skip&lt;br /&gt;
* &#039;&#039;&#039;limit&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): maximum values to reduce, or -1 for no limit&lt;br /&gt;
* &#039;&#039;&#039;reduce&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(acc:any, value:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): serial accumulator over complete values&lt;br /&gt;
* &#039;&#039;&#039;neutral&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): initial accumulator&lt;br /&gt;
* &#039;&#039;&#039;producer&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(emit:func) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): nested streaming plan called with a one-value emit callback&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== window_mut ==&lt;br /&gt;
&lt;br /&gt;
Ring buffer shift-insert for window functions. (window_mut window emit_fn vals) writes vals (a list of stride values) into the current slot, increments counter. If skip&amp;amp;gt;0, decrements skip. Otherwise calls (emit_fn oldest_v0 oldest_v1 ... newest_v0 newest_v1) with all slot values ordered oldest-to-newest. Returns updated window.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;window&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): ring buffer accumulator&lt;br /&gt;
* &#039;&#039;&#039;emit_fn&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(values:any...) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): callback receiving all window values oldest-to-newest&lt;br /&gt;
* &#039;&#039;&#039;vals&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of stride values to insert&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== window_flush ==&lt;br /&gt;
&lt;br /&gt;
Flush remaining window buffer by shifting in nils. (window_flush window emit_fn count) shifts in count positions of nils, calling emit_fn for each displaced position. Returns nil.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;window&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): ring buffer accumulator&lt;br /&gt;
* &#039;&#039;&#039;emit_fn&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(values:any...) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): callback receiving all window values oldest-to-newest&lt;br /&gt;
* &#039;&#039;&#039;count&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of nil positions to shift in&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;nil&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== show_processlist ==&lt;br /&gt;
&lt;br /&gt;
returns a list of active sessions for SHOW [FULL] PROCESSLIST; pass true for full info&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;full&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): if true, include full Info text &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== connection_id ==&lt;br /&gt;
&lt;br /&gt;
returns the process-list ID of the current session (MySQL CONNECTION_ID() equivalent)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== kill_query ==&lt;br /&gt;
&lt;br /&gt;
cancel the running query in session id; returns true if a query was killed&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;id&#039;&#039;&#039; (&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;): session ID from SHOW PROCESSLIST&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Full_SCM_API_documentation&amp;diff=296</id>
		<title>Full SCM API documentation</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Full_SCM_API_documentation&amp;diff=296"/>
		<updated>2026-08-27T06:38:23Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Window Functions]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Timezone]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
* [[Transactions]]&lt;br /&gt;
* [[JIT in Scheme|JIT]]&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Vectors&amp;diff=295</id>
		<title>Vectors</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Vectors&amp;diff=295"/>
		<updated>2026-08-27T06:37:29Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Vectors =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Vectors&#039;&#039;&#039; module provides vector mathematics functionality for the SCM programming language. This module includes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Vector operations&#039;&#039;&#039;: Functions to perform mathematical operations on vectors (dot)&lt;br /&gt;
* &#039;&#039;&#039;Distance calculations&#039;&#039;&#039;: Support for different distance metrics including DOT, COSINE, and EUCLIDEAN&lt;br /&gt;
&lt;br /&gt;
These functions provide essential tools for working with vectors in mathematical computations, enabling vector analysis and similarity calculations in SCM programs.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
== dot ==&lt;br /&gt;
&lt;br /&gt;
produced the dot product&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;v1&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): vector1&lt;br /&gt;
* &#039;&#039;&#039;v2&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): vector2&lt;br /&gt;
* &#039;&#039;&#039;mode&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): DOT, COSINE, EUCLIDEAN, default is DOT &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Transactions&amp;diff=294</id>
		<title>Transactions</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Transactions&amp;diff=294"/>
		<updated>2026-08-27T06:36:53Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot; ← Back to Full SCM API documentation   == tx_commit ==  Commits the current transaction.  &amp;#039;&amp;#039;&amp;#039;Allowed number of parameters:&amp;#039;&amp;#039;&amp;#039; 1–1  &amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; === Parameters ===  * &amp;#039;&amp;#039;&amp;#039;session&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;func(key:string?, value:any?) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): the session function that holds tx state  &amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; === Returns ===  &amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;  == tx_rollback ==  Rolls back the current transaction.  &amp;#039;&amp;#039;&amp;#039;Allowed number of parameters:&amp;#039;&amp;#039;&amp;#039; 1–1  &amp;lt;span...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== tx_commit ==&lt;br /&gt;
&lt;br /&gt;
Commits the current transaction.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;session&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(key:string?, value:any?) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): the session function that holds tx state&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== tx_rollback ==&lt;br /&gt;
&lt;br /&gt;
Rolls back the current transaction.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;session&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(key:string?, value:any?) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): the session function that holds tx state&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== with_autocommit ==&lt;br /&gt;
&lt;br /&gt;
Executes fn inside an implicit TxCursorStability transaction if no explicit transaction is active in session. Commits on success, rolls back on error, and re-raises any panic so the caller&#039;s error handler still fires. If an explicit transaction is active (session[&amp;amp;quot;transaction&amp;amp;quot;] != nil), fn is executed without any wrapping.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;session&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(key:string?, value:any?) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): the session function holding tx state&lt;br /&gt;
* &#039;&#039;&#039;fn&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;): zero-argument function to execute&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Full_SCM_API_documentation&amp;diff=293</id>
		<title>Full SCM API documentation</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Full_SCM_API_documentation&amp;diff=293"/>
		<updated>2026-08-27T06:36:39Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Timezone]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
* [[Transactions]]&lt;br /&gt;
* [[JIT in Scheme|JIT]]&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Timezone&amp;diff=292</id>
		<title>Timezone</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Timezone&amp;diff=292"/>
		<updated>2026-08-27T06:36:18Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
== unix_timestamp ==&lt;br /&gt;
&lt;br /&gt;
returns a unix timestamp (integer seconds since epoch)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dt&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): optional datetime value to convert &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== system_time_zone ==&lt;br /&gt;
&lt;br /&gt;
returns the operating system&#039;s local timezone name&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== convert_tz ==&lt;br /&gt;
&lt;br /&gt;
converts a datetime from one timezone to another&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dt&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): datetime value&lt;br /&gt;
* &#039;&#039;&#039;from_tz&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): source timezone&lt;br /&gt;
* &#039;&#039;&#039;to_tz&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): target timezone&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== from_unixtime ==&lt;br /&gt;
&lt;br /&gt;
converts a unix timestamp to a datetime in the session timezone&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;unix_ts&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): unix timestamp (seconds since epoch)&lt;br /&gt;
* &#039;&#039;&#039;format&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): optional MySQL format string &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== utc_timestamp ==&lt;br /&gt;
&lt;br /&gt;
returns the current UTC datetime&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== utc_date ==&lt;br /&gt;
&lt;br /&gt;
returns the current UTC date (midnight)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== utc_time ==&lt;br /&gt;
&lt;br /&gt;
returns the current UTC time (as a datetime at epoch date)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sysdate ==&lt;br /&gt;
&lt;br /&gt;
returns the current datetime (re-evaluated per call, unlike now())&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== at_time_zone ==&lt;br /&gt;
&lt;br /&gt;
PostgreSQL AT TIME ZONE operator: converts between timezones&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dt&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): datetime value&lt;br /&gt;
* &#039;&#039;&#039;zone&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): target timezone&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== timestampdiff ==&lt;br /&gt;
&lt;br /&gt;
returns the difference between two datetimes in the given unit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;unit&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR&lt;br /&gt;
* &#039;&#039;&#039;dt1&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first datetime&lt;br /&gt;
* &#039;&#039;&#039;dt2&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second datetime&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Timezone&amp;diff=291</id>
		<title>Timezone</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Timezone&amp;diff=291"/>
		<updated>2026-08-27T06:35:23Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot; == unix_timestamp ==  returns a unix timestamp (integer seconds since epoch)  &amp;#039;&amp;#039;&amp;#039;Allowed number of parameters:&amp;#039;&amp;#039;&amp;#039; 0–1  &amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; === Parameters ===  * &amp;#039;&amp;#039;&amp;#039;dt&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): optional datetime value to convert &amp;#039;&amp;#039;(optional)&amp;#039;&amp;#039;  &amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; === Returns ===  &amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;  == system_time_zone ==  returns the operating system&amp;#039;s local timezone name  &amp;#039;&amp;#039;&amp;#039;Allowed number of parameters:&amp;#039;&amp;#039;&amp;#039; 0–0  &amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; === Para...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== unix_timestamp ==&lt;br /&gt;
&lt;br /&gt;
returns a unix timestamp (integer seconds since epoch)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dt&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): optional datetime value to convert &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== system_time_zone ==&lt;br /&gt;
&lt;br /&gt;
returns the operating system&#039;s local timezone name&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== convert_tz ==&lt;br /&gt;
&lt;br /&gt;
converts a datetime from one timezone to another&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dt&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): datetime value&lt;br /&gt;
* &#039;&#039;&#039;from_tz&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): source timezone&lt;br /&gt;
* &#039;&#039;&#039;to_tz&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): target timezone&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== from_unixtime ==&lt;br /&gt;
&lt;br /&gt;
converts a unix timestamp to a datetime in the session timezone&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;unix_ts&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): unix timestamp (seconds since epoch)&lt;br /&gt;
* &#039;&#039;&#039;format&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): optional MySQL format string &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== utc_timestamp ==&lt;br /&gt;
&lt;br /&gt;
returns the current UTC datetime&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== utc_date ==&lt;br /&gt;
&lt;br /&gt;
returns the current UTC date (midnight)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== utc_time ==&lt;br /&gt;
&lt;br /&gt;
returns the current UTC time (as a datetime at epoch date)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sysdate ==&lt;br /&gt;
&lt;br /&gt;
returns the current datetime (re-evaluated per call, unlike now())&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== at_time_zone ==&lt;br /&gt;
&lt;br /&gt;
PostgreSQL AT TIME ZONE operator: converts between timezones&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dt&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): datetime value&lt;br /&gt;
* &#039;&#039;&#039;zone&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): target timezone&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== timestampdiff ==&lt;br /&gt;
&lt;br /&gt;
returns the difference between two datetimes in the given unit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;unit&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR&lt;br /&gt;
* &#039;&#039;&#039;dt1&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first datetime&lt;br /&gt;
* &#039;&#039;&#039;dt2&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second datetime&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Full_SCM_API_documentation&amp;diff=290</id>
		<title>Full SCM API documentation</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Full_SCM_API_documentation&amp;diff=290"/>
		<updated>2026-08-27T06:35:15Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Timezone]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
* [[JIT in Scheme|JIT]]&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Sync&amp;diff=289</id>
		<title>Sync</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Sync&amp;diff=289"/>
		<updated>2026-08-27T06:29:25Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Sync =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Sync&#039;&#039;&#039; module provides synchronization and concurrency functionality for the SCM programming language. This module includes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Session management&#039;&#039;&#039;: Functions to create threadsafe key-value stores (newsession)&lt;br /&gt;
* &#039;&#039;&#039;Context handling&#039;&#039;&#039;: Context management with session support (context)&lt;br /&gt;
* &#039;&#039;&#039;Timing control&#039;&#039;&#039;: Functions to pause execution (sleep)&lt;br /&gt;
* &#039;&#039;&#039;Function caching&#039;&#039;&#039;: One-time execution wrappers with result caching (once)&lt;br /&gt;
* &#039;&#039;&#039;Thread synchronization&#039;&#039;&#039;: Mutex creation for serialized access (mutex)&lt;br /&gt;
&lt;br /&gt;
These functions provide essential tools for managing concurrent operations, shared state, and synchronization in multi-threaded SCM programs.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
== newpromise ==&lt;br /&gt;
&lt;br /&gt;
Creates a single-value promise cell (thread-safe via CAS spin-lock). Returns a tagPromise Scmer. (newpromise) allocates a [2]Scmer backing; (newpromise list) reuses an existing ≥2-element slice as backing with zero extra allocation. API: (p &amp;amp;quot;value&amp;amp;quot;) reads current value (nil if pending), (p &amp;amp;quot;value&amp;amp;quot; v) resolves, (p &amp;amp;quot;once&amp;amp;quot; v) resolves once (panics if already fulfilled/failed), (p &amp;amp;quot;once&amp;amp;quot; v msg) resolves once with custom panic message, (p &amp;amp;quot;state&amp;amp;quot;) returns state (nil/true/false), (p &amp;amp;quot;fail&amp;amp;quot;) sets failed and clears the stored value, (p &amp;amp;quot;fail&amp;amp;quot; err) sets failed and stores err as payload.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): optional: ≥2-element slice to use as backing &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func(operation:string, value:any?, msg:string?) -&amp;amp;gt; any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== newsession ==&lt;br /&gt;
&lt;br /&gt;
Creates a new session which is a threadsafe key-value store. Besides get/set/list, get_or_compute_scoped shares concurrent computation by a query-local handle.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func(key_or_operation:any?, value_scope_or_key:any?, key_or_producer:any?, scoped_producer:func?) -&amp;amp;gt; any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== with_session ==&lt;br /&gt;
&lt;br /&gt;
Executes a function with the given session installed in the execution context, so storage operations can access the session&#039;s transaction state.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;session&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(key:any?, value:any?) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): the session to install&lt;br /&gt;
* &#039;&#039;&#039;fn&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;): the function to execute&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== context ==&lt;br /&gt;
&lt;br /&gt;
Context helper function. Each context also contains a session. (context func args) creates a new context and runs func in that context, (context &amp;amp;quot;session&amp;amp;quot;) reads the session variable, (context &amp;amp;quot;check&amp;amp;quot;) will check the liveliness of the context and otherwise throw an error&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;args...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): depends on the usage &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sleep ==&lt;br /&gt;
&lt;br /&gt;
sleeps the amount of seconds&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;duration&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of seconds to sleep&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== once ==&lt;br /&gt;
&lt;br /&gt;
Creates a function wrapper that you can call multiple times but only gets executed once. The result value is cached and returned on a second call. You can add parameters to that resulting function that will be passed to the first run of the wrapped function.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;f&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;): function that produces the result value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func(args:any...) -&amp;amp;gt; any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== mutex ==&lt;br /&gt;
&lt;br /&gt;
Creates a context-aware mutex. The return value serializes calls to parameterless functions and stops waiting when the current request is cancelled.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func(fn:func) -&amp;amp;gt; any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== numcpu ==&lt;br /&gt;
&lt;br /&gt;
Returns the number of logical CPUs available for parallel execution&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== memstats ==&lt;br /&gt;
&lt;br /&gt;
Returns memory statistics as a dict with keys: alloc, total_alloc, sys, heap_alloc, heap_sys (all in bytes)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;dict&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;settimeout&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== setTimeout ==&lt;br /&gt;
&lt;br /&gt;
Schedules a callback to run after the given delay in milliseconds (fractional values allowed for sub-millisecond precision).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;callback&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(args:any...) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): function to execute once the timeout expires&lt;br /&gt;
* &#039;&#039;&#039;milliseconds&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): milliseconds until execution&lt;br /&gt;
* &#039;&#039;&#039;args...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): optional arguments forwarded to the callback &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;cleartimeout&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== clearTimeout ==&lt;br /&gt;
&lt;br /&gt;
Cancels a timeout created with setTimeout.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;id&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): identifier returned by setTimeout&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Strings&amp;diff=288</id>
		<title>Strings</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Strings&amp;diff=288"/>
		<updated>2026-08-27T06:24:31Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Strings =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Strings&#039;&#039;&#039; module provides comprehensive string manipulation and processing functions for the SCM programming language. This module includes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;String validation&#039;&#039;&#039;: Functions to check string types and properties (string?, strlen)&lt;br /&gt;
* &#039;&#039;&#039;String manipulation&#039;&#039;&#039;: Concatenation (concat), substring extraction (substr), and case conversion (toLower, toUpper)&lt;br /&gt;
* &#039;&#039;&#039;Pattern matching&#039;&#039;&#039;: Wildcard pattern matching (strlike) and string replacement (replace)&lt;br /&gt;
* &#039;&#039;&#039;String parsing&#039;&#039;&#039;: Splitting strings (split) and data type simplification (simplify)&lt;br /&gt;
* &#039;&#039;&#039;Encoding/Decoding&#039;&#039;&#039;: URL encoding/decoding, HTML entities, JSON processing, and binary conversion&lt;br /&gt;
* &#039;&#039;&#039;Internationalization&#039;&#039;&#039;: Collation support for natural sorting and language-specific comparisons&lt;br /&gt;
&lt;br /&gt;
These functions provide the essential tools for text processing, data formatting, and string-based operations in SCM programs.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;string&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== string? ==&lt;br /&gt;
&lt;br /&gt;
tells if the value is a string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== concat ==&lt;br /&gt;
&lt;br /&gt;
concatenates stringable values and returns a string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value to concat&lt;br /&gt;
* &#039;&#039;&#039;more...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): additional values to concat &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_concat ==&lt;br /&gt;
&lt;br /&gt;
SQL CONCAT semantics: returns NULL if any argument is NULL&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value to concat&lt;br /&gt;
* &#039;&#039;&#039;more...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): additional values to concat &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== substr ==&lt;br /&gt;
&lt;br /&gt;
returns a substring (0-based index)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): string to cut&lt;br /&gt;
* &#039;&#039;&#039;start&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): first character index (0-based)&lt;br /&gt;
* &#039;&#039;&#039;len&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): optional length &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_substr ==&lt;br /&gt;
&lt;br /&gt;
SQL SUBSTR/SUBSTRING with 1-based index and bounds checking&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): string to cut&lt;br /&gt;
* &#039;&#039;&#039;start&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): first character position (1-based)&lt;br /&gt;
* &#039;&#039;&#039;len&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): optional length &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== simplify ==&lt;br /&gt;
&lt;br /&gt;
turns a stringable input value in the easiest-most value (e.g. turn strings into numbers if they are numeric&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value to simplify&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== strlen ==&lt;br /&gt;
&lt;br /&gt;
returns the length of a string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== strlike ==&lt;br /&gt;
&lt;br /&gt;
matches the string against a wildcard pattern using SQL NULL semantics&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
* &#039;&#039;&#039;pattern&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): pattern with % and _ in them&lt;br /&gt;
* &#039;&#039;&#039;collation&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): collation in which to compare them &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== strlike_cs ==&lt;br /&gt;
&lt;br /&gt;
matches the string against a wildcard pattern case-sensitively using SQL NULL semantics&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
* &#039;&#039;&#039;pattern&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): pattern with % and _ in them&lt;br /&gt;
* &#039;&#039;&#039;collation&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): ignored (present for parser compatibility) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;tolower&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== toLower ==&lt;br /&gt;
&lt;br /&gt;
turns a string into lower case&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;toupper&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== toUpper ==&lt;br /&gt;
&lt;br /&gt;
turns a string into upper case&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== replace ==&lt;br /&gt;
&lt;br /&gt;
replaces all occurances in a string with another string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;s&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
* &#039;&#039;&#039;find&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): search string&lt;br /&gt;
* &#039;&#039;&#039;replace&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): replace string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== strtrim ==&lt;br /&gt;
&lt;br /&gt;
trims whitespace from both ends of a string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== strltrim ==&lt;br /&gt;
&lt;br /&gt;
trims whitespace from the left of a string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== strrtrim ==&lt;br /&gt;
&lt;br /&gt;
trims whitespace from the right of a string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_trim ==&lt;br /&gt;
&lt;br /&gt;
SQL TRIM(): NULL-safe trim of whitespace from both ends&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_ltrim ==&lt;br /&gt;
&lt;br /&gt;
SQL LTRIM(): NULL-safe trim of whitespace from left&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_rtrim ==&lt;br /&gt;
&lt;br /&gt;
SQL RTRIM(): NULL-safe trim of whitespace from right&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== split ==&lt;br /&gt;
&lt;br /&gt;
splits a string using a separator or space&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
* &#039;&#039;&#039;separator&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): (optional) parameter, defaults to &amp;amp;quot; &amp;amp;quot; &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== string_repeat ==&lt;br /&gt;
&lt;br /&gt;
repeats a string n times&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): string to repeat&lt;br /&gt;
* &#039;&#039;&#039;count&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of repetitions&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== collate ==&lt;br /&gt;
&lt;br /&gt;
returns a canonical order relation for a collation and direction. MemCP allows natural sorting of numeric literals.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;collation&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): collation string of the form LANG or LANG_cs or LANG_ci where LANG is a BCP 47 code, for compatibility to MySQL, a CHARSET_ prefix is allowed and ignored as well as the aliases bin, danish, general, german1, german2, spanish and swedish are allowed for language codes&lt;br /&gt;
* &#039;&#039;&#039;reverse&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): whether to reverse the order like in ORDER BY DESC &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func(a:any, b:any) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== htmlentities ==&lt;br /&gt;
&lt;br /&gt;
escapes the string for use in HTML&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== urlencode ==&lt;br /&gt;
&lt;br /&gt;
encodes a string according to URI coding schema&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): string to encode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== urldecode ==&lt;br /&gt;
&lt;br /&gt;
decodes a string according to URI coding schema&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): string to decode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_encode ==&lt;br /&gt;
&lt;br /&gt;
encodes a value in JSON, treats lists as lists&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value to encode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_quote ==&lt;br /&gt;
&lt;br /&gt;
quotes a string as JSON&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_encode_assoc ==&lt;br /&gt;
&lt;br /&gt;
encodes a value in JSON, treats lists as associative arrays&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value to encode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_decode ==&lt;br /&gt;
&lt;br /&gt;
parses JSON into a map&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): string to decode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_decode_scmer ==&lt;br /&gt;
&lt;br /&gt;
parses JSON produced by json_encode and preserves Scheme symbols and lists&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-28&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): Scmer JSON to decode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-28&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== base64_encode ==&lt;br /&gt;
&lt;br /&gt;
encodes a string as Base64 (standard encoding)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-29&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): binary string to encode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-29&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== base64_decode ==&lt;br /&gt;
&lt;br /&gt;
decodes a Base64 string (standard encoding)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-30&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): base64-encoded string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-30&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_unescape ==&lt;br /&gt;
&lt;br /&gt;
unescapes the inner part of a sql string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-31&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): string to decode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-31&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== bin2hex ==&lt;br /&gt;
&lt;br /&gt;
turns binary data into hex with lowercase letters&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-32&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): string to encode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-32&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;bin2hex-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== bin2hex ==&lt;br /&gt;
&lt;br /&gt;
turns binary data into hex with lowercase letters&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-33&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): string to encode&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-33&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== hex2bin ==&lt;br /&gt;
&lt;br /&gt;
decodes a hex string into binary data&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-34&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): hex string (even length)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-34&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== uuid ==&lt;br /&gt;
&lt;br /&gt;
generates a new random UUID v4 string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-35&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-35&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;randombytes&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== randomBytes ==&lt;br /&gt;
&lt;br /&gt;
returns a string with numBytes cryptographically secure random bytes&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-36&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;numBytes&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of random bytes&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-36&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== regexp_replace ==&lt;br /&gt;
&lt;br /&gt;
replaces matches of a regex pattern in a string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-37&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;str&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
* &#039;&#039;&#039;pattern&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): regex pattern&lt;br /&gt;
* &#039;&#039;&#039;replacement&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): replacement string&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-37&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== fnv_hash ==&lt;br /&gt;
&lt;br /&gt;
computes a fast non-cryptographic 64-bit FNV-1a hash of a string, returns a 16-character hex string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-38&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;str&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string to hash&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-38&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== stable_structural_hash ==&lt;br /&gt;
&lt;br /&gt;
streams the string or serialized representation of a Scheme value into stable FNV-1a without constructing the complete representation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-39&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value to hash&lt;br /&gt;
* &#039;&#039;&#039;serialize&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): use the Scheme serializer instead of string rendering &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-39&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sha1 ==&lt;br /&gt;
&lt;br /&gt;
computes the SHA-1 digest of a string, returns a 40-character lowercase hex string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-40&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;str&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string to hash&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-40&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sha256 ==&lt;br /&gt;
&lt;br /&gt;
computes the SHA-256 digest of a string, returns a 64-character lowercase hex string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-41&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;str&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string to hash&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-41&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== regexp_test ==&lt;br /&gt;
&lt;br /&gt;
tests if a string matches a regex pattern, returns true/false&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-42&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;str&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): input string&lt;br /&gt;
* &#039;&#039;&#039;pattern&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): regex pattern&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-42&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_parse_bson ==&lt;br /&gt;
&lt;br /&gt;
validates JSON and returns a BSON-backed value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-43&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-43&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_array ==&lt;br /&gt;
&lt;br /&gt;
creates a MySQL-compatible JSON array&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-44&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-44&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_object ==&lt;br /&gt;
&lt;br /&gt;
creates a MySQL-compatible JSON object&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-45&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-45&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;json_quote-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== json_quote ==&lt;br /&gt;
&lt;br /&gt;
quotes a string as JSON&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-46&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-46&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_unquote ==&lt;br /&gt;
&lt;br /&gt;
unquotes a JSON string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-47&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-47&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_valid ==&lt;br /&gt;
&lt;br /&gt;
tests whether a value contains valid JSON&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-48&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-48&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_type ==&lt;br /&gt;
&lt;br /&gt;
returns the MySQL JSON type name&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-49&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-49&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_depth ==&lt;br /&gt;
&lt;br /&gt;
returns maximum JSON document depth&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-50&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-50&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_length ==&lt;br /&gt;
&lt;br /&gt;
returns JSON object or array length&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-51&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-51&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_extract ==&lt;br /&gt;
&lt;br /&gt;
extracts one or more JSON paths&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-52&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-52&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_keys ==&lt;br /&gt;
&lt;br /&gt;
returns object member names&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-53&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-53&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_contains_path ==&lt;br /&gt;
&lt;br /&gt;
tests whether one or all JSON paths exist&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-54&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-54&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_contains ==&lt;br /&gt;
&lt;br /&gt;
tests JSON containment&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-55&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-55&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_overlaps ==&lt;br /&gt;
&lt;br /&gt;
tests whether JSON values overlap&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-56&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-56&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_member_of ==&lt;br /&gt;
&lt;br /&gt;
tests whether a JSON scalar is a member of an array&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-57&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-57&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_pretty ==&lt;br /&gt;
&lt;br /&gt;
pretty-prints JSON&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-58&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-58&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_storage_size ==&lt;br /&gt;
&lt;br /&gt;
returns BSON payload size&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-59&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-59&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_storage_free ==&lt;br /&gt;
&lt;br /&gt;
returns unused BSON storage space&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-60&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-60&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_schema_valid ==&lt;br /&gt;
&lt;br /&gt;
validates a document against a MySQL Draft 4 JSON schema&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-61&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-61&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_schema_validation_report ==&lt;br /&gt;
&lt;br /&gt;
reports MySQL Draft 4 JSON schema validation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-62&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-62&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_set ==&lt;br /&gt;
&lt;br /&gt;
sets or inserts JSON path values&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-63&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-63&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_insert ==&lt;br /&gt;
&lt;br /&gt;
inserts missing JSON path values&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-64&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-64&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_replace ==&lt;br /&gt;
&lt;br /&gt;
replaces existing JSON path values&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-65&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-65&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_remove ==&lt;br /&gt;
&lt;br /&gt;
removes JSON path values&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-66&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-66&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_array_append ==&lt;br /&gt;
&lt;br /&gt;
appends values to JSON arrays&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-67&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-67&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_array_insert ==&lt;br /&gt;
&lt;br /&gt;
inserts values into JSON arrays&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-68&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-68&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_merge_patch ==&lt;br /&gt;
&lt;br /&gt;
merges documents using RFC 7396 semantics&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-69&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-69&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_merge_preserve ==&lt;br /&gt;
&lt;br /&gt;
merges documents while preserving values&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-70&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-70&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_search ==&lt;br /&gt;
&lt;br /&gt;
searches JSON string values&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-71&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-71&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_value ==&lt;br /&gt;
&lt;br /&gt;
extracts a scalar JSON value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-72&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-72&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_to_json ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL to_json and to_jsonb&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-73&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-73&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_row_to_json ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL row_to_json&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-74&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-74&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_build_array ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL JSON array builders&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-75&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-75&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_array_absent ==&lt;br /&gt;
&lt;br /&gt;
implements SQL/JSON ARRAY ABSENT ON NULL&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-76&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-76&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_build_object ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL JSON object builders&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-77&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-77&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_object ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL json_object and jsonb_object array forms&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-78&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-78&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_serialize ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL json_serialize&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-79&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-79&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_array_length ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL json_array_length&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-80&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-80&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_extract_path ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL json_extract_path&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-81&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-81&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_extract_path_text ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL json_extract_path_text&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-82&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-82&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_set ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb_set&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-83&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-83&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_set_lax ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb_set_lax&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-84&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-84&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_insert ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb_insert&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-85&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-85&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_strip_nulls ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL json_strip_nulls&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-86&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-86&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_typeof ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL json_typeof&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-87&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-87&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_populate_record_valid ==&lt;br /&gt;
&lt;br /&gt;
validates PostgreSQL jsonb_populate_record input shape&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-88&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-88&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_concat ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb concatenation&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-89&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-89&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_delete ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb deletion&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-90&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-90&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_delete_path ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb path deletion&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-91&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-91&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_subtract ==&lt;br /&gt;
&lt;br /&gt;
dispatches PostgreSQL numeric and jsonb subtraction&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-92&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-92&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_exists ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb top-level existence&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-93&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-93&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_path_exists ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb_path_exists&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-94&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-94&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_path_match ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb_path_match&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-95&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-95&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_path_query_array ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb_path_query_array&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-96&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-96&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_jsonb_path_query_first ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL jsonb_path_query_first&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-97&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-97&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_value ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL SQL/JSON JSON_VALUE&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-98&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-98&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_get ==&lt;br /&gt;
&lt;br /&gt;
implements PostgreSQL JSON object and array extraction&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-99&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-99&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_arrayagg_entry ==&lt;br /&gt;
&lt;br /&gt;
wraps one JSON_ARRAYAGG input value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-100&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-100&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_arrayagg_reduce ==&lt;br /&gt;
&lt;br /&gt;
JSON_ARRAYAGG reducer&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-101&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-101&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_arrayagg_finalize ==&lt;br /&gt;
&lt;br /&gt;
builds one BSON array from a collected JSON_ARRAYAGG value list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-102&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-102&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_objectagg_entry ==&lt;br /&gt;
&lt;br /&gt;
constructs a JSON_OBJECTAGG key/value entry&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-103&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-103&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== json_objectagg_reduce ==&lt;br /&gt;
&lt;br /&gt;
JSON_OBJECTAGG reducer&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-104&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-104&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pg_json_table_rows ==&lt;br /&gt;
&lt;br /&gt;
materializes a PostgreSQL JSON table function as rows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-105&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-105&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Streams&amp;diff=287</id>
		<title>Streams</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Streams&amp;diff=287"/>
		<updated>2026-08-27T06:23:44Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Streams =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Streams&#039;&#039;&#039; module provides stream processing and compression functionality for the SCM programming language. This module includes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Stream creation&#039;&#039;&#039;: Functions to create streams from string content (streamString)&lt;br /&gt;
* &#039;&#039;&#039;Compression&#039;&#039;&#039;: Stream compression using gzip and xz algorithms&lt;br /&gt;
* &#039;&#039;&#039;Decompression&#039;&#039;&#039;: Stream decompression using zcat (gzip) and xzcat (xz) functions&lt;br /&gt;
&lt;br /&gt;
These functions enable efficient handling of data streams, file compression, and decompression operations in SCM programs, particularly useful for processing large datasets and file I/O operations.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;streamstring&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== streamString ==&lt;br /&gt;
&lt;br /&gt;
creates a stream that contains a string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;content&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): content to put into the stream&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== gzip ==&lt;br /&gt;
&lt;br /&gt;
compresses a stream with gzip. Create streams with (stream filename)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;stream&#039;&#039;&#039; (&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;): input stream&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== xz ==&lt;br /&gt;
&lt;br /&gt;
compresses a stream with xz. Create streams with (stream filename)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;stream&#039;&#039;&#039; (&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;): input stream&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== zcat ==&lt;br /&gt;
&lt;br /&gt;
turns a compressed gzip stream into a stream of uncompressed data. Create streams with (stream filename)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;stream&#039;&#039;&#039; (&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;): input stream&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== xzcat ==&lt;br /&gt;
&lt;br /&gt;
turns a compressed xz stream into a stream of uncompressed data. Create streams with (stream filename)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;stream&#039;&#039;&#039; (&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;): input stream&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Storage&amp;diff=286</id>
		<title>Storage</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Storage&amp;diff=286"/>
		<updated>2026-08-27T06:20:08Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Storage =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Storage&#039;&#039;&#039; module provides functions to manage databases, tables, columns, keys, partitions, and large data operations in SCM.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== table ==&lt;br /&gt;
&lt;br /&gt;
resolves a schema+table name pair into a table handle&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== scan_estimate ==&lt;br /&gt;
&lt;br /&gt;
estimate output row count for a table scan&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== table_planner_statistics ==&lt;br /&gt;
&lt;br /&gt;
return the immutable O(1) planner-statistics snapshot for a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== scan_selectivity_estimate ==&lt;br /&gt;
&lt;br /&gt;
bounded estimate of visible rows matching a table filter; stops at max_rows and does not log scan telemetry&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 5–5&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tx&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): transaction context to use for visibility; usually ((context &amp;amp;quot;session&amp;amp;quot;) &amp;amp;quot;__memcp_tx&amp;amp;quot;)&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;condition_cols&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;condition&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;max_rows&#039;&#039;&#039; (&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;table_empty&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== table_empty? ==&lt;br /&gt;
&lt;br /&gt;
returns true if a table currently has no rows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== scan_recset ==&lt;br /&gt;
&lt;br /&gt;
builds a query-local record-set handle from one table scan, or -- when given an existing recset instead of a table -- narrows that recset to the members which also satisfy filter, re-evaluating filter only over its existing membership. The latter is the cheap way to AND a further (possibly subscan-heavy) condition onto an already-narrowed recset without re-touching rows outside it (e.g. evaluating an expensive correlated check only over the rows a cheap selective filter already narrowed a table down to). The returned value is not persisted and can be scanned like a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tx&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): transaction context to use for visibility; usually ((context &amp;amp;quot;session&amp;amp;quot;) &amp;amp;quot;__memcp_tx&amp;amp;quot;)&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): a table, or an existing recset to narrow further&lt;br /&gt;
* &#039;&#039;&#039;filterColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;filter&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): lambda function that decides whether a row enters the recset&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;recset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== recset_count ==&lt;br /&gt;
&lt;br /&gt;
returns the number of currently stored recids in a query-local recset&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;recset&#039;&#039;&#039; (&amp;lt;code&amp;gt;recset&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== recset_project_join ==&lt;br /&gt;
&lt;br /&gt;
projects a source recset through key columns into a query-local target-table recset&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 5–5&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tx&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): transaction context to use for visibility; usually ((context &amp;amp;quot;session&amp;amp;quot;) &amp;amp;quot;__memcp_tx&amp;amp;quot;)&lt;br /&gt;
* &#039;&#039;&#039;source_recset&#039;&#039;&#039; (&amp;lt;code&amp;gt;recset&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;source_key_columns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;target_table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;target_key_columns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;recset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== recset_key_index ==&lt;br /&gt;
&lt;br /&gt;
builds an immutable lookup function for key columns of the rows contained in a query-local recset&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tx&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): transaction context used while reading source keys&lt;br /&gt;
* &#039;&#039;&#039;source_recset&#039;&#039;&#039; (&amp;lt;code&amp;gt;recset&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;source_key_columns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func(key:any...) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== recset_union ==&lt;br /&gt;
&lt;br /&gt;
combines query-local recsets from the same table and removes duplicate record IDs&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;recsets&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;recset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== recset_intersect ==&lt;br /&gt;
&lt;br /&gt;
intersects query-local recsets from the same table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;recsets&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;recset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== recset_difference ==&lt;br /&gt;
&lt;br /&gt;
returns the records from the first query-local recset which occur in none of the following same-table recsets&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;recsets&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;recset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== recset_not ==&lt;br /&gt;
&lt;br /&gt;
returns the complement of a query-local recset relative to the currently visible rows of its base table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;recset&#039;&#039;&#039; (&amp;lt;code&amp;gt;recset&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;recset&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== scan_exists ==&lt;br /&gt;
&lt;br /&gt;
returns true if a table contains at least one visible row matching the given filter; uses scan boundary analysis without map/reduce setup&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tx&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): transaction context to use for visibility; usually ((context &amp;amp;quot;session&amp;amp;quot;) &amp;amp;quot;__memcp_tx&amp;amp;quot;)&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table|list|recset&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;filterColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;filter&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): lambda function that decides whether a row exists&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== scan ==&lt;br /&gt;
&lt;br /&gt;
does an unordered parallel filter-map-reduce pass on a single table and returns the reduced result&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 6–10&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tx&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): transaction context to use for visibility and mutations; usually ((context &amp;amp;quot;session&amp;amp;quot;) &amp;amp;quot;__memcp_tx&amp;amp;quot;)&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table|list|recset&amp;lt;/code&amp;gt;): table handle, query-local recset, or a list for temporary data&lt;br /&gt;
* &#039;&#039;&#039;filterColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): physical columns passed to filter before map/reduce; $recset_contains supplies a row-bound RecSet membership closure&lt;br /&gt;
* &#039;&#039;&#039;filter&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): lambda function that decides whether a dataset is passed to the map phase. You can use any column of that table as lambda parameter. You should structure your lambda with an (and) at the root element. Every equal? &amp;amp;lt; &amp;amp;gt; &amp;amp;lt;= &amp;amp;gt;= will possibly translated to an indexed scan&lt;br /&gt;
* &#039;&#039;&#039;mapColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): physical columns passed to map after filtering; pseudo columns are $update (update/delete current row), $recset_contains (row-bound RecSet membership), $set:&amp;lt;column&amp;gt;, $increment:&amp;lt;column&amp;gt;, and $invalidate:&amp;lt;column&amp;gt; (computed-column maintenance), plus NEW.&amp;lt;column&amp;gt; in trigger plans&lt;br /&gt;
* &#039;&#039;&#039;map&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): lambda function to extract data from the dataset. You can use any column of that table as lambda parameter. You can return a value you want to extract and pass to reduce, but you can also directly call insert, print or resultrow functions. If you declare a parameter named &#039;&amp;lt;math display=&amp;quot;inline&amp;quot;&amp;gt;update&#039;, this variable will hold a function that you can use to delete or update a row. Call (&amp;lt;/math&amp;gt;update) to delete the dataset, call ($update &#039;(&amp;amp;quot;field1&amp;amp;quot; value1 &amp;amp;quot;field2&amp;amp;quot; value2)) to update certain columns.&lt;br /&gt;
* &#039;&#039;&#039;reduce&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(any, any)&amp;lt;/code&amp;gt;): (optional) lambda function to aggregate the map results. It takes two parameters (a b) where a is the accumulator and b the new value. The accumulator for the first reduce call is the neutral element. The return value will be the accumulator input for the next reduce call. There are two reduce phases: shard-local and shard-collect. In the shard-local phase, a starts with neutral and b is fed with the return values of each map call. In the shard-collect phase, a starts with neutral and b is fed with the result of each shard-local pass. &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;neutral&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): (optional) neutral element for the reduce phase, otherwise nil is assumed &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;reduce2&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(any, any)&amp;lt;/code&amp;gt;): (optional) second stage reduce function that will apply a result of reduce to the neutral element/accumulator &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;isOuter&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): (optional) if true, in case of no hits, call map once anyway with NULL values &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== scan_batch ==&lt;br /&gt;
&lt;br /&gt;
does an unordered parallel filter-map-reduce pass on a single table using batchdata-backed #N pseudo columns and returns the reduced result&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 8–12&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tx&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): transaction context to use for visibility and mutations; usually ((context &amp;amp;quot;session&amp;amp;quot;) &amp;amp;quot;__memcp_tx&amp;amp;quot;)&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table|list|recset&amp;lt;/code&amp;gt;): table handle, query-local recset, or a list for temporary data&lt;br /&gt;
* &#039;&#039;&#039;filterColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of columns that are fed into filter; #0, #1, ... address batchdata slots&lt;br /&gt;
* &#039;&#039;&#039;filter&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): lambda function that decides whether a dataset is passed to the map phase&lt;br /&gt;
* &#039;&#039;&#039;mapColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of columns that are fed into map; #0, #1, ... address batchdata slots&lt;br /&gt;
* &#039;&#039;&#039;map&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): lambda function to extract data from the dataset&lt;br /&gt;
* &#039;&#039;&#039;stride&#039;&#039;&#039; (&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;): number of batchdata entries per batch row&lt;br /&gt;
* &#039;&#039;&#039;batchdata&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): flat batch buffer accessed via #N pseudo columns&lt;br /&gt;
* &#039;&#039;&#039;reduce&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(any, any)&amp;lt;/code&amp;gt;): (optional) lambda function to aggregate the map results &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;neutral&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): (optional) neutral element for the reduce phase, otherwise nil is assumed &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;reduce2&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(any, any)&amp;lt;/code&amp;gt;): (optional) second stage reduce function that will apply a result of reduce to the neutral element/accumulator &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;isOuter&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): (optional) if true, in case of no hits, call map once anyway with NULL values &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== scan_order_batch_accept ==&lt;br /&gt;
&lt;br /&gt;
incrementally scans a table or existing RecSet in scan_order order and applies a RecSet batch filter before OFFSET/LIMIT and map/reduce. The first candidate RecSet contains offset+limit rows; if too few rows are accepted, subsequent disjoint batches contain twice as many candidates until the accepted limit is satisfied or the input is exhausted. batchFilter is called as (batchFilter input_recset) and must return an exact subset RecSet of the same base table and transaction. A simple batchFilter may call (scan_recset tx input_recset filterColumns realFilter); complex filters may project input_recset to another table, apply search/ACL scans and project the result back to the input table. The returned RecSet is used only as a membership mask against the already ordered candidate vector, so output order is preserved without scanning the unordered RecSet again. For non-unique ORDER BY values, include an explicit unique tie-breaker. sortcols/sortdirs may both be empty; that path greedily collects candidates without sorting. limitPartitionCols is present for scan_order signature compatibility and currently must be 0&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 10–14&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tx&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): transaction context used consistently by the candidate scan and every batch filter operation; usually ((context &amp;amp;quot;session&amp;amp;quot;) &amp;amp;quot;__memcp_tx&amp;amp;quot;)&lt;br /&gt;
* &#039;&#039;&#039;table_or_recset&#039;&#039;&#039; (&amp;lt;code&amp;gt;table|recset&amp;lt;/code&amp;gt;): base table or complete existing query-local RecSet from which ordered candidate batches are drawn&lt;br /&gt;
* &#039;&#039;&#039;batchFilter&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(input_recset:recset) -&amp;amp;gt; recset&amp;lt;/code&amp;gt;): function (lambda (input_recset) accepted_recset). It may naively narrow input_recset with scan_recset, or run arbitrary RecSet projections/search/ACL operations and project back. It must return a same-table, same-transaction subset of input_recset&lt;br /&gt;
* &#039;&#039;&#039;sortcols&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): same as scan_order: columns or computed sort functions. Include a unique tie-breaker for a total repeatable order; use an empty list for greedy unsorted collection&lt;br /&gt;
* &#039;&#039;&#039;sortdirs&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): same as scan_order: one relation per sort column (&amp;amp;lt;, &amp;amp;gt; or collate relation); must also be empty when sortcols is empty&lt;br /&gt;
* &#039;&#039;&#039;limitPartitionCols&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): reserved for scan_order signature compatibility; currently must be 0&lt;br /&gt;
* &#039;&#039;&#039;offset&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of batch-filter-accepted rows to skip; it is not the number of driver candidates already examined&lt;br /&gt;
* &#039;&#039;&#039;limit&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): finite maximum number of accepted rows passed to map; the initial candidate batch size is offset+limit and doubles for every subsequent batch&lt;br /&gt;
* &#039;&#039;&#039;mapColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): physical columns passed to map after filtering; pseudo columns are $update (update/delete current row), $recset_contains (row-bound RecSet membership), $set:&amp;lt;column&amp;gt;, $increment:&amp;lt;column&amp;gt;, and $invalidate:&amp;lt;column&amp;gt; (computed-column maintenance), plus NEW.&amp;lt;column&amp;gt; in trigger plans; $break is reserved for internal ORC convergence and must not implement SQL OFFSET/LIMIT, which belong in the native offset and limit arguments&lt;br /&gt;
* &#039;&#039;&#039;map&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): same map callback contract as scan_order; accepted record IDs are passed to its shard mapper in batches&lt;br /&gt;
* &#039;&#039;&#039;reduce&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(acc:any, val:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): optional serial reducer over mapped accepted rows, with the same accumulator contract as scan_order &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;neutral&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): optional neutral element for reduce; defaults to nil &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;isOuter&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): optional scan_order-compatible outer behavior: map one NULL row when no accepted row reaches map &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;notFoundValue&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): optional result when no accepted row reaches map and isOuter is false; defaults to neutral &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== scan_order ==&lt;br /&gt;
&lt;br /&gt;
does an ordered parallel filter and serial map-reduce pass on a single table and returns the reduced result&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 11–17&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tx&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): transaction context to use for visibility and mutations; usually ((context &amp;amp;quot;session&amp;amp;quot;) &amp;amp;quot;__memcp_tx&amp;amp;quot;)&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table|list|recset&amp;lt;/code&amp;gt;): table handle, query-local RecSet, or a list for temporary data&lt;br /&gt;
* &#039;&#039;&#039;filterColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): physical columns passed to filter before map/reduce; $recset_contains supplies a row-bound RecSet membership closure&lt;br /&gt;
* &#039;&#039;&#039;filter&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): lambda function that decides whether a dataset is passed to the map phase. You can use any column of that table as lambda parameter. You should structure your lambda with an (and) at the root element. Every equal? &amp;amp;lt; &amp;amp;gt; &amp;amp;lt;= &amp;amp;gt;= will possibly translated to an indexed scan&lt;br /&gt;
* &#039;&#039;&#039;sortcols&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of columns to sort. Each column is either a string to point to an existing column or a func(cols...)-&amp;amp;gt;any to compute a sortable value&lt;br /&gt;
* &#039;&#039;&#039;sortdirs&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of column directions to sort. Must be same length as sortcols. &amp;amp;lt; means ascending, &amp;amp;gt; means descending, (collate ...) will add collations&lt;br /&gt;
* &#039;&#039;&#039;limitPartitionCols&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of leading sort columns that form the partition key for per-partition offset/limit. 0 (default) means global offset/limit.&lt;br /&gt;
* &#039;&#039;&#039;offset&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of globally ordered, filter-accepted items to skip before map; apply SQL OFFSET here rather than in map&lt;br /&gt;
* &#039;&#039;&#039;limit&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): maximum globally ordered, filter-accepted items passed to map; -1 means unlimited; apply SQL LIMIT here so shard-local Top-K and the global merge can brake early&lt;br /&gt;
* &#039;&#039;&#039;mapColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): physical columns passed to map after filtering; pseudo columns are $update (update/delete current row), $recset_contains (row-bound RecSet membership), $set:&amp;lt;column&amp;gt;, $increment:&amp;lt;column&amp;gt;, and $invalidate:&amp;lt;column&amp;gt; (computed-column maintenance), plus NEW.&amp;lt;column&amp;gt; in trigger plans; $break is reserved for internal ORC convergence and must not implement SQL OFFSET/LIMIT, which belong in the native offset and limit arguments&lt;br /&gt;
* &#039;&#039;&#039;map&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): lambda function to extract data from the dataset. You can use any column of that table as lambda parameter. You can return a value you want to extract and pass to reduce, but you can also directly call insert, print or resultrow functions. If you declare a parameter named &#039;&amp;lt;math display=&amp;quot;inline&amp;quot;&amp;gt;update&#039;, this variable will hold a function that you can use to delete or update a row. Call (&amp;lt;/math&amp;gt;update) to delete the dataset, call ($update &#039;(&amp;amp;quot;field1&amp;amp;quot; value1 &amp;amp;quot;field2&amp;amp;quot; value2)) to update certain columns.&lt;br /&gt;
* &#039;&#039;&#039;reduce&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(acc:any, val:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): (optional) lambda function to aggregate the map results. It takes two parameters (a b) where a is the accumulator and b the new value. The accumulator for the first reduce call is the neutral element. The return value will be the accumulator input for the next reduce call. There are two reduce phases: shard-local and shard-collect. In the shard-local phase, a starts with neutral and b is fed with the return values of each map call. In the shard-collect phase, a starts with neutral and b is fed with the result of each shard-local pass. &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;neutral&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): (optional) neutral element for the reduce phase, otherwise nil is assumed &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;isOuter&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): (optional) if true, in case of no hits, call map once anyway with NULL values &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;notFoundValue&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): (optional) result for no hits when isOuter is false; defaults to neutral &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;postOrderFilterColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): (optional) columns for a predicate evaluated in global order before OFFSET/LIMIT are counted; use for expensive acceptance checks that cannot participate in index boundaries &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;postOrderFilter&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): (optional) late acceptance predicate. Rejected rows do not count toward OFFSET/LIMIT and never reach map. SQL plans use this instead of callback-driven $break control flow &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== scan_order_multi ==&lt;br /&gt;
&lt;br /&gt;
does an ordered parallel filter and serial map-reduce pass across multiple tables simultaneously, merging results into a single sorted stream&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 13–17&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tx&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): transaction context&lt;br /&gt;
* &#039;&#039;&#039;tables&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of table handles&lt;br /&gt;
* &#039;&#039;&#039;filterColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of filter column lists, one per table&lt;br /&gt;
* &#039;&#039;&#039;filterFns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of filter lambdas, one per table&lt;br /&gt;
* &#039;&#039;&#039;sortcols&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of sort column lists, one per table&lt;br /&gt;
* &#039;&#039;&#039;sortdirs&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of sort direction comparators (shared)&lt;br /&gt;
* &#039;&#039;&#039;perTableOffset&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): per-table offset (list of int; -1 disables)&lt;br /&gt;
* &#039;&#039;&#039;perTableLimit&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): per-table limit (list of int; -1 disables)&lt;br /&gt;
* &#039;&#039;&#039;limitPartitionCols&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of leading sort columns forming partition key&lt;br /&gt;
* &#039;&#039;&#039;offset&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of items to skip (global)&lt;br /&gt;
* &#039;&#039;&#039;limit&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): max number of items to read (global; -1 = unlimited)&lt;br /&gt;
* &#039;&#039;&#039;mapColumns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of map column lists, one per table&lt;br /&gt;
* &#039;&#039;&#039;mapFns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of map lambdas, one per table&lt;br /&gt;
* &#039;&#039;&#039;reduce&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;): (optional) aggregation function &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;neutral&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): (optional) neutral element for reduce &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;isOuter&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): (optional) if true, emit null row when no hits &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;notFoundValue&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): (optional) result for no hits when isOuter is false; defaults to neutral &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== createdatabase ==&lt;br /&gt;
&lt;br /&gt;
creates a new database&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the new database&lt;br /&gt;
* &#039;&#039;&#039;ignoreexists&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): if true, return false instead of throwing an error &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== dropdatabase ==&lt;br /&gt;
&lt;br /&gt;
drops a database&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the database&lt;br /&gt;
* &#039;&#039;&#039;ifexists&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): if true, don&#039;t throw an error if it doesn&#039;t exist &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== checktablemaintenance ==&lt;br /&gt;
&lt;br /&gt;
checks whether a user-initiated maintenance operation is allowed for a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;operation&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== maintenance_capabilities ==&lt;br /&gt;
&lt;br /&gt;
returns the server-side maintenance capabilities for a database or table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== createtable ==&lt;br /&gt;
&lt;br /&gt;
creates a table, runs its oninit option and registered after-create-table lifecycle triggers synchronously, and returns only after initialization completes; concurrent if-not-exists callers wait for that same completion&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–5&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the existing database that will contain the table&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the table to create&lt;br /&gt;
* &#039;&#039;&#039;cols&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): column and constraint definitions: (&amp;amp;quot;column&amp;amp;quot; name type dimensions typeparams), (&amp;amp;quot;unique&amp;amp;quot; name columns), or (&amp;amp;quot;foreign&amp;amp;quot; name local_columns referenced_table referenced_columns update_mode delete_mode). dimensions is a list of integer type dimensions. typeparams is an alternating key/value list supporting primary (bool), unique (bool), auto_increment (bool), null (bool), default (any), default_expression (string), update (expression), comment (string), collate (string), temp (bool), filtercols (string list), filter (function), sortcols (string list), sortdirs (bool list), partitioncount (integer), mapcols (string list), mapfn (function), reducefn (function), and reduceinit (any). Column lists are string lists; foreign-key modes are restrict, cascade, or set null&lt;br /&gt;
* &#039;&#039;&#039;options&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): alternating key/value list; supported keys are engine (safe, logged, sloppy, memory, or cache), collation (string), charset (string), comment (string), auto_increment (non-negative integer), and oninit (closed zero-argument function run synchronously once per data generation; concurrent if-not-exists callers wait for it, and memory/cache tables persist the callback so the first idempotent createtable after restart repopulates their empty data)&lt;br /&gt;
* &#039;&#039;&#039;ifnotexists&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): when true, return false instead of failing if the table exists; if another caller is still creating it, wait for that caller&#039;s after-create-table initialization before returning false &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== createcolumn ==&lt;br /&gt;
&lt;br /&gt;
creates a new column in table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 5–7&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;colname&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the new column&lt;br /&gt;
* &#039;&#039;&#039;type&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the basetype&lt;br /&gt;
* &#039;&#039;&#039;dimensions&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): dimensions of the type (e.g. for decimal)&lt;br /&gt;
* &#039;&#039;&#039;options&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): assoc list: primary, unique, auto_increment, null, comment, default, default_expression, collate; ORC: sortcols, sortdirs, partitioncount, mapcols, mapfn, reducefn, reduceinit&lt;br /&gt;
* &#039;&#039;&#039;computorCols&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of columns that is passed into params of computor &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;computor&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(columns:any...) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): lambda expression that can take other column values and computes the value of that column &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== createkey ==&lt;br /&gt;
&lt;br /&gt;
creates a new key on a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;keyname&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the new key&lt;br /&gt;
* &#039;&#039;&#039;unique&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): whether the key is unique&lt;br /&gt;
* &#039;&#039;&#039;columns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of columns to include&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== createforeignkey ==&lt;br /&gt;
&lt;br /&gt;
creates a new foreign key on a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 7–7&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table1&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;keyname&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the new key&lt;br /&gt;
* &#039;&#039;&#039;columns1&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of columns to include&lt;br /&gt;
* &#039;&#039;&#039;table2&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;columns2&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of columns to include&lt;br /&gt;
* &#039;&#039;&#039;updatemode&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): restrict|cascade|set null&lt;br /&gt;
* &#039;&#039;&#039;deletemode&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): restrict|cascade|set null&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== shardcolumn ==&lt;br /&gt;
&lt;br /&gt;
tells us how it would partition a column according to their values. Returns a list of pivot elements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;colname&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the column&lt;br /&gt;
* &#039;&#039;&#039;numpartitions&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of partitions; optional. leave 0 if you want to detect the partiton number automatically or copy the partition schema of the table &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== partitiontable ==&lt;br /&gt;
&lt;br /&gt;
suggests a partition scheme for a table. If the table has no partition scheme yet, it will immediately apply that scheme and return true. If the table already has a partition scheme, it will alter the partitioning score such that the partitioning scheme is considered in the next repartitioning and return false.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-28&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;columns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): associative list of string -&amp;amp;gt; list representing column name -&amp;amp;gt; pivots. You can compute pivots by (shardcolumn ...)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-28&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== altertable ==&lt;br /&gt;
&lt;br /&gt;
alters a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-29&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;operation&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): one of owner|drop|engine|collation|auto_increment&lt;br /&gt;
* &#039;&#039;&#039;parameter&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): name of the column to drop or value of the parameter&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-29&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== altercolumn ==&lt;br /&gt;
&lt;br /&gt;
alters a column&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-30&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;column&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the column&lt;br /&gt;
* &#039;&#039;&#039;operation&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): one of drop|type|collation|auto_increment|comment&lt;br /&gt;
* &#039;&#039;&#039;parameter&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): name of the column to drop or value of the parameter&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-30&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== droptable ==&lt;br /&gt;
&lt;br /&gt;
removes a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-31&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;ifexists&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): if true, don&#039;t throw an error if it already exists &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-31&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== dropcolumn ==&lt;br /&gt;
&lt;br /&gt;
drops a column from a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-32&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;column&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the column to drop&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-32&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== migratedropcolumn ==&lt;br /&gt;
&lt;br /&gt;
drops a legacy system column during startup migration&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-33&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;column&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): legacy column name&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-33&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== invalidatecolumn ==&lt;br /&gt;
&lt;br /&gt;
marks all values of a computed column as stale&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-34&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;column&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the computed column&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-34&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== invalidateorc ==&lt;br /&gt;
&lt;br /&gt;
invalidates ORC column rows from a sort key onwards via validMask scan&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-35&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;column&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the ORC column&lt;br /&gt;
* &#039;&#039;&#039;sortkeys&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): composite sort key values from which to invalidate&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-35&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== register_keytable_cleanup ==&lt;br /&gt;
&lt;br /&gt;
registers triggers on a base table to maintain keytable entries (insert/delete group keys)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-36&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;base_table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;kt_table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;tblvar&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): table alias used in scan column prefixes&lt;br /&gt;
* &#039;&#039;&#039;key_pairs&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of (base_col kt_col) pairs&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-36&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== initialize_cache_table ==&lt;br /&gt;
&lt;br /&gt;
registers maintenance, locks source tables for a consistent snapshot, and runs a canonical planner-cache initializer exactly once&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 5–6&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-37&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;transaction&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): explicit transaction context carrying query-session ownership&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;source_tables&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;register_maintenance&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;initializer&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;finalizer&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;): optional zero-argument finalizer run under the same source-table locks after initialization &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-37&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== touch_keytable ==&lt;br /&gt;
&lt;br /&gt;
extends the lease on a keytable so CacheManager defers eviction&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-38&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-38&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== locktables ==&lt;br /&gt;
&lt;br /&gt;
acquires WRITE or READ user-level locks on a list of tables (LOCK TABLES); implicitly releases any previously held locks&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-39&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;locks&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): flat list of schema, table, write? triples&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-39&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== unlocktables ==&lt;br /&gt;
&lt;br /&gt;
releases all user-level table locks held by this session&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-40&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-40&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== get_fk_target ==&lt;br /&gt;
&lt;br /&gt;
returns (ref_table ref_column) if a single-column FK exists for the given column, nil otherwise&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-41&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;column&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): column name&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-41&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== renametable ==&lt;br /&gt;
&lt;br /&gt;
renames a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-42&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the database&lt;br /&gt;
* &#039;&#039;&#039;oldname&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): current name of the table&lt;br /&gt;
* &#039;&#039;&#039;newname&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): new name of the table&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-42&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== insert ==&lt;br /&gt;
&lt;br /&gt;
inserts a new dataset into table and returns the number of successful items&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–7&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-43&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;columns&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of column names, e.g. &#039;(&amp;amp;quot;ID&amp;amp;quot;, &amp;amp;quot;value&amp;amp;quot;)&lt;br /&gt;
* &#039;&#039;&#039;datasets&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of list of column values, e.g. &#039;(&#039;(1 10) &#039;(2 15))&lt;br /&gt;
* &#039;&#039;&#039;onCollisionCols&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of columns of the old dataset that have to be passed to onCollision. Can also request $update, $set:&amp;lt;computed-column&amp;gt;, or NEW.&amp;lt;insert-column&amp;gt;. &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;onCollision&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;): function called for each collision. Its positional parameters are the values requested by onCollisionCols, in the same order. If omitted, collisions raise an error. &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;mergeNull&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): if true, it will handle NULL values as equal according to SQL 2003&#039;s definition of DISTINCT (https://en.wikipedia.org/wiki/Null_(SQL)#When_two_nulls_are_equal:_grouping,_sorting,_and_some_set_operations) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;onInsertid&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(id:number) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): (optional) callback (id)-&amp;amp;gt;any; called once with the first auto_increment id assigned for this INSERT &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-43&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== stat ==&lt;br /&gt;
&lt;br /&gt;
return system statistics as assoc: mem_available, mem_total, process_memory, shard_memory, shard_budget, persisted_memory, persisted_budget, cache_entry_count, cache_entry_size. (stat schema) and (stat schema tbl) return a string with detailed memory usage.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-44&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): (optional) database name for detailed string output &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): (optional) table name for detailed string output &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-44&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== totalmem ==&lt;br /&gt;
&lt;br /&gt;
Returns total physical memory in bytes (from /proc/meminfo)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-45&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-45&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== resolve_column_name ==&lt;br /&gt;
&lt;br /&gt;
resolve a physical column name from immutable table metadata&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-46&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): database name&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): table name&lt;br /&gt;
* &#039;&#039;&#039;column&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): column name&lt;br /&gt;
* &#039;&#039;&#039;ignorecase&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): whether identifier case is ignored&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-46&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== show ==&lt;br /&gt;
&lt;br /&gt;
show databases/tables/columns/shards&lt;br /&gt;
&lt;br /&gt;
(show) lists database names (show schema) lists table names (show table_handle) lists the memoized column defs (show table_handle true) returns table metadata (show table_handle &amp;amp;quot;statistics&amp;amp;quot;) returns index statistics (show schema true) lists tables with full info: [{name,engine,row_count,size_bytes,collation,comment},...] (show schema tbl) lists column defs (show schema tbl true) returns assoc {columns,meta,shards} (show schema tbl N) returns shard N overview assoc {shard,state,main_count,delta,deletions,size_bytes} (show schema tbl N true) returns shard N full assoc adding columns and indexes (show schema tbl &amp;amp;quot;statistics&amp;amp;quot;) returns index statistics (used by INFORMATION_SCHEMA)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-47&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema_or_table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|table|recset&amp;lt;/code&amp;gt;): (optional) database name or resolved table/recset handle &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;table_or_property&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|bool&amp;lt;/code&amp;gt;): (optional) table name, true for full info, or &amp;amp;quot;statistics&amp;amp;quot; for a handle &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;property&#039;&#039;&#039; (&amp;lt;code&amp;gt;int|bool|string&amp;lt;/code&amp;gt;): (optional) shard index (int), true for full table info, or &amp;amp;quot;statistics&amp;amp;quot; &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;full&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): (optional) true to include columns and indexes in shard detail &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-47&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== show_triggers ==&lt;br /&gt;
&lt;br /&gt;
show triggers for a given table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-48&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): database name&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): (optional) table name, if omitted shows all triggers in schema &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-48&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== rebuild ==&lt;br /&gt;
&lt;br /&gt;
rebuilds main storages and returns the amount of time it took; with a table handle, rebuilds only that table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-49&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table_or_all&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool|table&amp;lt;/code&amp;gt;): table handle for a table-local rebuild; otherwise whether to rebuild unchanged shards globally (default: false) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;all_or_repartition&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): with a table: whether to rebuild unchanged shards; globally: whether to repartition (default: true) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;repartition&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): with a table handle, whether to repartition that table (default: true) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-49&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;loadcsv&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== loadCSV ==&lt;br /&gt;
&lt;br /&gt;
loads a CSV stream into a table and returns the amount of time it took. The first line of the file must be the headlines. The headlines must match the table&#039;s columns exactly.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–5&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-50&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the database&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the table&lt;br /&gt;
* &#039;&#039;&#039;stream&#039;&#039;&#039; (&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;): CSV file, load with: (stream filename)&lt;br /&gt;
* &#039;&#039;&#039;delimiter&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): (optional) delimiter defaults to &amp;amp;quot;;&amp;amp;quot; &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;firstline&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): (optional) if the first line contains the column names (otherwise, the tables column order is used) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-50&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;loadjson&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== loadJSON ==&lt;br /&gt;
&lt;br /&gt;
loads a .jsonl file from stream into a database and returns the amount of time it took. JSONL is a linebreak separated file of JSON objects. Each JSON object is one dataset in the database. Before you add rows, you must declare the table in a line &#039;#table &amp;lt;tablename&amp;gt;&#039;. All other lines starting with # are comments. Columns are created dynamically as soon as they occur in a json object.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-51&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the database where you want to put the tables in&lt;br /&gt;
* &#039;&#039;&#039;stream&#039;&#039;&#039; (&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;): stream of the .jsonl file, read with: (stream filename)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-51&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== settings ==&lt;br /&gt;
&lt;br /&gt;
reads or writes a global settings value. This modifies your data/settings.json.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-52&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;key&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the key to set or get (for reference, rts) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): new value of that setting &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-52&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== createcreatetabletrigger ==&lt;br /&gt;
&lt;br /&gt;
registers a lifecycle trigger that fires synchronously after a future createtable for the given schema/table succeeds&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 6–6&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-53&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the database&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the table to watch for creation&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the trigger&lt;br /&gt;
* &#039;&#039;&#039;source_sql&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): original SQL body text (for diagnostics)&lt;br /&gt;
* &#039;&#039;&#039;body&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): trigger body (Scheme procedure or deferred trigger expression)&lt;br /&gt;
* &#039;&#039;&#039;visible&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): true = user trigger, false = internal trigger&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-53&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== dropcreatetabletrigger ==&lt;br /&gt;
&lt;br /&gt;
removes a registered create-table lifecycle trigger&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-54&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the database&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the table watched for creation&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the trigger&lt;br /&gt;
* &#039;&#039;&#039;ifexists&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): don&#039;t throw error if trigger doesn&#039;t exist&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-54&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== createtrigger ==&lt;br /&gt;
&lt;br /&gt;
creates a new trigger on a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 6–6&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-55&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;table&#039;&#039;&#039; (&amp;lt;code&amp;gt;table&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the trigger&lt;br /&gt;
* &#039;&#039;&#039;timing&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): one of: before_insert, after_insert, before_update, after_update, before_delete, after_delete&lt;br /&gt;
* &#039;&#039;&#039;source_sql&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): original SQL body text (for SHOW TRIGGERS)&lt;br /&gt;
* &#039;&#039;&#039;body&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): trigger body (parsed Scheme expression)&lt;br /&gt;
* &#039;&#039;&#039;visible&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): true = user trigger (shown in SHOW TRIGGERS), false = internal trigger (hidden)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-55&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== droptrigger ==&lt;br /&gt;
&lt;br /&gt;
removes a trigger from a table&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-56&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;schema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the database&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): name of the trigger&lt;br /&gt;
* &#039;&#039;&#039;ifexists&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): don&#039;t throw error if trigger doesn&#039;t exist&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-56&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== mysql_import ==&lt;br /&gt;
&lt;br /&gt;
imports schema+data from a MySQL server into MemCP&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–8&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-57&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;host&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): MySQL host (nil =&amp;amp;gt; 127.0.0.1)&lt;br /&gt;
* &#039;&#039;&#039;port&#039;&#039;&#039; (&amp;lt;code&amp;gt;int|nil&amp;lt;/code&amp;gt;): MySQL port (nil =&amp;amp;gt; 3306)&lt;br /&gt;
* &#039;&#039;&#039;username&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): MySQL username&lt;br /&gt;
* &#039;&#039;&#039;password&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): MySQL password&lt;br /&gt;
* &#039;&#039;&#039;sourcedb&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): source database (omit/nil =&amp;amp;gt; all non-system dbs) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;targetdb&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): target database (omit/nil =&amp;amp;gt; sourcedb) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;sourcetable&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): source table (omit/nil =&amp;amp;gt; all tables in sourcedb) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;targettable&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): target table (omit/nil =&amp;amp;gt; sourcetable) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-57&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== psql_import ==&lt;br /&gt;
&lt;br /&gt;
imports schema+data from a PostgreSQL server into MemCP&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–9&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-58&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;host&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): PostgreSQL host (nil =&amp;amp;gt; 127.0.0.1)&lt;br /&gt;
* &#039;&#039;&#039;port&#039;&#039;&#039; (&amp;lt;code&amp;gt;int|nil&amp;lt;/code&amp;gt;): PostgreSQL port (nil =&amp;amp;gt; 5432)&lt;br /&gt;
* &#039;&#039;&#039;username&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): PostgreSQL username&lt;br /&gt;
* &#039;&#039;&#039;password&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): PostgreSQL password&lt;br /&gt;
* &#039;&#039;&#039;sourcedb&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): source database (omit/nil =&amp;amp;gt; all non-system dbs) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;sourceschema&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): source schema (omit/nil =&amp;amp;gt; all non-system schemas in sourcedb) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;targetdb&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): target database (omit/nil =&amp;amp;gt; sourcedb) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;sourcetable&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): source table (omit/nil =&amp;amp;gt; all tables in sourceschema) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;targettable&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|nil&amp;lt;/code&amp;gt;): target table (omit/nil =&amp;amp;gt; sourcetable) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-58&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=SCM_Builtins&amp;diff=285</id>
		<title>SCM Builtins</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=SCM_Builtins&amp;diff=285"/>
		<updated>2026-08-27T06:19:26Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= SCM Builtins =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;SCM Builtins&#039;&#039;&#039; module provides the core foundational functions for the SCM (Scheme) programming language implementation. These built-in functions handle essential operations including:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Language constructs&#039;&#039;&#039;: Control flow (if, and, or), variable management (define, set), and code evaluation (eval, quote)&lt;br /&gt;
* &#039;&#039;&#039;Function operations&#039;&#039;&#039;: Lambda creation, function application, and error handling (try, error)&lt;br /&gt;
* &#039;&#039;&#039;Data manipulation&#039;&#039;&#039;: Type conversion (string, symbol), list operations, and pattern matching&lt;br /&gt;
* &#039;&#039;&#039;Development tools&#039;&#039;&#039;: Code optimization, timing measurements, and debugging support&lt;br /&gt;
* &#039;&#039;&#039;Execution control&#039;&#039;&#039;: Parallel processing, variable scoping, and source code annotation&lt;br /&gt;
&lt;br /&gt;
This module forms the foundation upon which all other SCM functionality is built, providing the essential primitives needed for Scheme programming.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== quote ==&lt;br /&gt;
&lt;br /&gt;
returns a symbol or list without evaluating it&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;symbol&#039;&#039;&#039; (&amp;lt;code&amp;gt;symbol&amp;lt;/code&amp;gt;): symbol to quote&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;symbol&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== eval ==&lt;br /&gt;
&lt;br /&gt;
executes the given scheme program in the current environment&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;code&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list with head and optional parameters&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== size ==&lt;br /&gt;
&lt;br /&gt;
compute the memory size of a value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value to examine&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== optimize ==&lt;br /&gt;
&lt;br /&gt;
optimize the given scheme program and optionally report telemetry after completion&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;code&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list with head and optional parameters&lt;br /&gt;
* &#039;&#039;&#039;telemetry_callback&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(assoc) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): optional callback invoked once with optimizer telemetry &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== time ==&lt;br /&gt;
&lt;br /&gt;
measures the time it takes to compute the first argument&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;code&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): code to execute&lt;br /&gt;
* &#039;&#039;&#039;label&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): label to print in the log or trace &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== if ==&lt;br /&gt;
&lt;br /&gt;
checks a condition and then conditionally evaluates code branches; there might be multiple condition+true-branch clauses&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;condition...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): condition to evaluate&lt;br /&gt;
* &#039;&#039;&#039;true-branch...&#039;&#039;&#039; (&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;): code to evaluate if condition is true&lt;br /&gt;
* &#039;&#039;&#039;false-branch&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): code to evaluate if condition is false &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== and ==&lt;br /&gt;
&lt;br /&gt;
lazily combines conditions using SQL three-valued logic; returns false on the first false value, nil for UNKNOWN, otherwise true&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;condition&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): condition to evaluate &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== or ==&lt;br /&gt;
&lt;br /&gt;
lazily combines conditions using SQL three-valued logic; returns true on the first true value, nil for UNKNOWN, otherwise false&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;condition&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): condition to evaluate &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== coalesce ==&lt;br /&gt;
&lt;br /&gt;
returns the first value that has a non-zero value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;): value to examine &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;coalescenil&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== coalesceNil ==&lt;br /&gt;
&lt;br /&gt;
returns the first value that has a non-nil value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;): value to examine &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== define ==&lt;br /&gt;
&lt;br /&gt;
defines or sets a variable in the current environment&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;variable&#039;&#039;&#039; (&amp;lt;code&amp;gt;symbol&amp;lt;/code&amp;gt;): variable to set&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;): value to set the variable to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== set ==&lt;br /&gt;
&lt;br /&gt;
defines or sets a variable in the current environment&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;variable&#039;&#039;&#039; (&amp;lt;code&amp;gt;symbol&amp;lt;/code&amp;gt;): variable to set&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;): value to set the variable to&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== error ==&lt;br /&gt;
&lt;br /&gt;
halts the whole execution thread and throws an error message&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value or message to throw &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== try ==&lt;br /&gt;
&lt;br /&gt;
tries to execute a function and returns its result. In case of a failure, the error is fed to the second function and its result value will be used&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;func&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;): function with no parameters that will be called&lt;br /&gt;
* &#039;&#039;&#039;errorhandler&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(error:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): function that takes the error as parameter&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== apply ==&lt;br /&gt;
&lt;br /&gt;
runs the function with its arguments&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;function&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;): function to execute&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of arguments to apply&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== apply_assoc ==&lt;br /&gt;
&lt;br /&gt;
runs the function with its arguments but arguments is a assoc list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;function&#039;&#039;&#039; (&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;): function to execute (must be a lambda)&lt;br /&gt;
* &#039;&#039;&#039;arguments&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): assoc list of arguments to apply&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;symbol&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== symbol ==&lt;br /&gt;
&lt;br /&gt;
returns a symbol built from that string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): string value that will be converted into a symbol&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;symbol&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== list ==&lt;br /&gt;
&lt;br /&gt;
constructs a list from its arguments&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;items&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): items to put into the list &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== for ==&lt;br /&gt;
&lt;br /&gt;
Sequential loop over a list state; applies a condition and step function and returns the final state list. Use only when iterations have strong data dependencies and must run sequentially.&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
&lt;br /&gt;
* Count to 10: (for &#039;(0) (lambda (x) (&amp;amp;lt; x 10)) (lambda (x) (list (+ x 1)))) =&amp;amp;gt; &#039;(10)&lt;br /&gt;
* Sum 0..9: (for &#039;(0 0) (lambda (x sum) (&amp;amp;lt; x 10)) (lambda (x sum) (list (+ x 1) (+ sum x)))) =&amp;amp;gt; &#039;(10 45)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;init&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): initial state as a list&lt;br /&gt;
* &#039;&#039;&#039;condition&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(state:any...) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): func that receives the current state as parameters and must return true if the loop shall be continued&lt;br /&gt;
* &#039;&#039;&#039;step&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(state:any...) -&amp;amp;gt; list&amp;lt;/code&amp;gt;): step func that returns the next state as a list&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== string ==&lt;br /&gt;
&lt;br /&gt;
converts the given value into string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): any value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== match ==&lt;br /&gt;
&lt;br /&gt;
takes a value evaluates the branch that first matches the given pattern Patterns can be any of:&lt;br /&gt;
&lt;br /&gt;
* symbol matches any value and stores is into a variable&lt;br /&gt;
* &amp;amp;quot;string&amp;amp;quot; (matches only this string)&lt;br /&gt;
* number (matches only this value)&lt;br /&gt;
* (symbol &amp;amp;quot;something&amp;amp;quot;) will only match the symbol &#039;something&#039;&lt;br /&gt;
* &#039;(subpattern subpattern...) matches a list with exactly these subpatterns&lt;br /&gt;
* (concat str1 str2 str3) will decompose a string into one of the following patterns: &amp;amp;quot;prefix&amp;amp;quot; variable, variable &amp;amp;quot;postfix&amp;amp;quot;, variable &amp;amp;quot;infix&amp;amp;quot; variable&lt;br /&gt;
* (cons a b) will reverse the cons function, so it will match the head of the list with a and the rest with b&lt;br /&gt;
* (regex &amp;amp;quot;pattern&amp;amp;quot; text var1 var2...) will match the given regex pattern, store the whole string into text and all capture groups into var1, var2...&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value to evaluate&lt;br /&gt;
* &#039;&#039;&#039;pattern...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): pattern&lt;br /&gt;
* &#039;&#039;&#039;result...&#039;&#039;&#039; (&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;): result value when the pattern matches; this code can use the variables matched in the pattern&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): (optional) value that is returned when no pattern matches &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== lambda ==&lt;br /&gt;
&lt;br /&gt;
returns a function (func) constructed from the given code&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;parameters&#039;&#039;&#039; (&amp;lt;code&amp;gt;symbol|list|nil&amp;lt;/code&amp;gt;): if you provide a parameter list, you will have named parameters. If you provide a single symbol, the list of parameters will be provided in that symbol&lt;br /&gt;
* &#039;&#039;&#039;code&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value that is evaluated when the lambda is called. code can use the parameters provided in the declaration as well es the scope above&lt;br /&gt;
* &#039;&#039;&#039;numvars&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of unnamed variables that can be accessed via (var 0) (var 1) etc. &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== begin ==&lt;br /&gt;
&lt;br /&gt;
creates a own variable scope, evaluates all sub expressions and returns the result of the last one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;expression...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): expressions to evaluate &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== parallel ==&lt;br /&gt;
&lt;br /&gt;
executes all parameters in parallel and returns nil if they are finished&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;expression...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): expressions to evaluate in parallel &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== source ==&lt;br /&gt;
&lt;br /&gt;
annotates the node with filename and line information for better backtraces&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;filename&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): Filename of the code&lt;br /&gt;
* &#039;&#039;&#039;line&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): Line of the code&lt;br /&gt;
* &#039;&#039;&#039;column&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): Column of the code&lt;br /&gt;
* &#039;&#039;&#039;code&#039;&#039;&#039; (&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;): code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;returntype&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== source_coverage_report ==&lt;br /&gt;
&lt;br /&gt;
returns Scheme source coverage statistics, optionally filtered by source path prefix&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;prefix&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): source path prefix &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;assoc&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== scheme ==&lt;br /&gt;
&lt;br /&gt;
parses a scheme expression into a list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;code&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): Scheme code&lt;br /&gt;
* &#039;&#039;&#039;filename&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): optional filename &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== serialize ==&lt;br /&gt;
&lt;br /&gt;
serializes a piece of code into a (hopefully) reparsable string; you shall be able to send that code over network and reparse with (scheme)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;code&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): Scheme code&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== pretty_print ==&lt;br /&gt;
&lt;br /&gt;
formats Scheme code as an indented, human-readable string; expressions up to width characters are kept on one line, longer ones are expanded with one argument per line&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-28&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;code&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): Scheme code to format&lt;br /&gt;
* &#039;&#039;&#039;width&#039;&#039;&#039; (&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;): max characters before expanding (default 20) &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-28&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Parsers&amp;diff=284</id>
		<title>Parsers</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Parsers&amp;diff=284"/>
		<updated>2026-08-27T06:17:42Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Parsers =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Parsers&#039;&#039;&#039; module provides parsing functionality for the SCM programming language. This module includes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Parser creation&#039;&#039;&#039;: Functions to create custom parsers using grammar syntax (parser)&lt;br /&gt;
* &#039;&#039;&#039;Grammar support&#039;&#039;&#039;: Support for various parser types including AtomParser, RegexParser, AndParser, OrParser, KleeneParser, ManyParser, MaybeParser, and more&lt;br /&gt;
* &#039;&#039;&#039;Packrat parsing&#039;&#039;&#039;: Implementation of packrat parsing algorithms for efficient parsing&lt;br /&gt;
* &#039;&#039;&#039;Whitespace handling&#039;&#039;&#039;: Configurable whitespace skipping mechanisms&lt;br /&gt;
&lt;br /&gt;
These functions provide essential tools for creating custom parsers and processing structured text data in SCM programs.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== parser ==&lt;br /&gt;
&lt;br /&gt;
creates a parser&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Scm parsers work this way:&lt;br /&gt;
(parser syntax scmerresult) -&amp;amp;gt; func&lt;br /&gt;
&lt;br /&gt;
syntax can be one of:&lt;br /&gt;
(parser syntax scmerresult) will execute scmerresult after parsing syntax&lt;br /&gt;
(parser syntax scmerresult &amp;amp;quot;skipper&amp;amp;quot;) will add a different whitespace skipper regex to the root parser&lt;br /&gt;
(define var syntax) valid inside (parser...), stores the result of syntax into var for use in scmerresult&lt;br /&gt;
&amp;amp;quot;str&amp;amp;quot; AtomParser&lt;br /&gt;
(atom &amp;amp;quot;str&amp;amp;quot; caseinsensitive skipws) AtomParser&lt;br /&gt;
(regex &amp;amp;quot;asdf&amp;amp;quot; caseinsensitive skipws) RegexParser&lt;br /&gt;
&#039;(a b c) AndParser&lt;br /&gt;
(or a b c) OrParser&lt;br /&gt;
(* sub separator noMemo) KleeneParser&lt;br /&gt;
(+ sub separator) ManyParser&lt;br /&gt;
(? xyz) MaybeParser (if &amp;amp;gt;1 AndParser)&lt;br /&gt;
(not mainparser parser1 parser2 parser3 ...) a parser that matches mainparser but not parser1...&lt;br /&gt;
(capture subparser) wraps a parser and returns (matched_text parsed_result)&lt;br /&gt;
$ EndParser&lt;br /&gt;
empty EmptyParser&lt;br /&gt;
symbol -&amp;amp;gt; use other parser defined in env&lt;br /&gt;
&lt;br /&gt;
for further details on packrat parsers, take a look at https://github.com/launix-de/go-packrat&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;syntax&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): syntax of the grammar (see docs)&lt;br /&gt;
* &#039;&#039;&#039;generator&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): (optional) expressions to evaluate. All captured variables are available in the scope. &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;skipper&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): (optional) string that defines the skip mechanism for whitespaces as regexp &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Lists&amp;diff=283</id>
		<title>Lists</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Lists&amp;diff=283"/>
		<updated>2026-08-27T06:15:56Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Lists =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Lists&#039;&#039;&#039; module provides comprehensive list manipulation and processing functions for the SCM programming language. This module includes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;List operations&#039;&#039;&#039;: Basic operations like counting (count), accessing elements (nth), and type checking (list?)&lt;br /&gt;
* &#039;&#039;&#039;List construction&#039;&#039;&#039;: Building lists with append, cons, and unique operations (append_unique, merge_unique)&lt;br /&gt;
* &#039;&#039;&#039;List deconstruction&#039;&#039;&#039;: Extracting parts with car (head), cdr (tail), and filtering operations&lt;br /&gt;
* &#039;&#039;&#039;Functional programming&#039;&#039;&#039;: Higher-order functions like map, filter, reduce, and produce for advanced list processing&lt;br /&gt;
* &#039;&#039;&#039;List utilities&#039;&#039;&#039;: Searching (has?, contains?), merging, zipping, and flattening operations&lt;br /&gt;
* &#039;&#039;&#039;List generation&#039;&#039;&#039;: Creating sequences and ranges with produce and produceN functions&lt;br /&gt;
&lt;br /&gt;
These functions provide the essential tools for working with lists as the primary data structure in functional programming with SCM.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== list ==&lt;br /&gt;
&lt;br /&gt;
constructs a list from its arguments&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;items&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): items to put into the list &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== count ==&lt;br /&gt;
&lt;br /&gt;
counts the number of elements in the list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): base list&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== nth ==&lt;br /&gt;
&lt;br /&gt;
get the nth item of a list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): base list&lt;br /&gt;
* &#039;&#039;&#039;index&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): index beginning from 0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== slice ==&lt;br /&gt;
&lt;br /&gt;
extract a sublist from start (inclusive) to end (exclusive). (slice list start end) returns elements list[start..end).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): base list&lt;br /&gt;
* &#039;&#039;&#039;start&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): start index (inclusive)&lt;br /&gt;
* &#039;&#039;&#039;end&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): end index (exclusive)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== reverse ==&lt;br /&gt;
&lt;br /&gt;
returns a new list with elements in reversed order.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list to reverse&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== append ==&lt;br /&gt;
&lt;br /&gt;
appends items to a list and return the extended list. The original list stays unharmed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): base list&lt;br /&gt;
* &#039;&#039;&#039;item...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): items to add &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== append_unique ==&lt;br /&gt;
&lt;br /&gt;
appends items to a list but only if they are new. The original list stays unharmed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): base list&lt;br /&gt;
* &#039;&#039;&#039;item...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): items to add &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== cons ==&lt;br /&gt;
&lt;br /&gt;
constructs a list from a head and a tail list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;car&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): new head element&lt;br /&gt;
* &#039;&#039;&#039;cdr&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): tail that is appended after car&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== car ==&lt;br /&gt;
&lt;br /&gt;
extracts the head of a list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== cdr ==&lt;br /&gt;
&lt;br /&gt;
extracts the tail of a list The tail of a list is a list with all items except the head.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== cadr ==&lt;br /&gt;
&lt;br /&gt;
extracts the second element of a list. Equivalent to (car (cdr x)).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== zip ==&lt;br /&gt;
&lt;br /&gt;
swaps the dimension of a list of lists. If one parameter is given, it is a list of lists that is flattened. If multiple parameters are given, they are treated as the components that will be zipped into the sub list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): list of lists of items &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== merge ==&lt;br /&gt;
&lt;br /&gt;
flattens a list of lists into a list containing all the subitems. If one parameter is given, it is a list of lists that is flattened. If multiple parameters are given, they are treated as lists that will be merged into one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): list of lists of items &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== merge_unique ==&lt;br /&gt;
&lt;br /&gt;
flattens a list of lists into a list containing all the subitems. Duplicates are filtered out.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list of lists of items &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;has&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== has? ==&lt;br /&gt;
&lt;br /&gt;
checks if a list has a certain item (equal?)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;haystack&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list to search in&lt;br /&gt;
* &#039;&#039;&#039;needle&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): item to search for&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== filter ==&lt;br /&gt;
&lt;br /&gt;
returns a list that only contains elements that pass the filter function&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list that has to be filtered&lt;br /&gt;
* &#039;&#039;&#039;condition&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(item:any) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): filter condition func(item)-&amp;amp;gt;bool&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== find ==&lt;br /&gt;
&lt;br /&gt;
returns the first list element that passes the condition function, or nil/default if none matches&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list to search&lt;br /&gt;
* &#039;&#039;&#039;condition&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(item:any) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): predicate func(any)-&amp;amp;gt;bool that is applied until the first match&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): optional default value if nothing matches &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== map ==&lt;br /&gt;
&lt;br /&gt;
returns a list that contains the results of a map function that is applied to the list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list that has to be mapped&lt;br /&gt;
* &#039;&#039;&#039;map&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(item:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): map function func(any)-&amp;amp;gt;any that is applied to each item&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== parallel_map ==&lt;br /&gt;
&lt;br /&gt;
like map, but applies fn to each element in parallel using a worker pool limited to runtime.NumCPU()&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list to map over in parallel&lt;br /&gt;
* &#039;&#039;&#039;fn&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(item:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): function applied to each element&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== parallel_map_mut ==&lt;br /&gt;
&lt;br /&gt;
like parallel_map, but signals the optimizer that fn may have side effects&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list to map over in parallel&lt;br /&gt;
* &#039;&#039;&#039;fn&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(item:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): function with side effects applied to each element&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;mapindex&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== mapIndex ==&lt;br /&gt;
&lt;br /&gt;
returns a list that contains the results of a map function that is applied to the list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list that has to be mapped&lt;br /&gt;
* &#039;&#039;&#039;map&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(index:int, item:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): map function func(i, any)-&amp;amp;gt;any that is applied to each item&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== reduce ==&lt;br /&gt;
&lt;br /&gt;
returns a list that contains the result of a map function&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list that has to be reduced&lt;br /&gt;
* &#039;&#039;&#039;reduce&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(acc:any, item:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): reduce function func(any any)-&amp;amp;gt;any where the first parameter is the accumulator, the second is a list item&lt;br /&gt;
* &#039;&#039;&#039;neutral&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): (optional) initial value of the accumulator, defaults to nil &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== produce ==&lt;br /&gt;
&lt;br /&gt;
returns a list that contains produced items - it works like for(state = startstate, condition(state), state = iterator(state)) {yield state}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;startstate&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): start state to begin with&lt;br /&gt;
* &#039;&#039;&#039;condition&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(state:any) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): func that returns true whether the state will be inserted into the result or the loop is stopped&lt;br /&gt;
* &#039;&#039;&#039;iterator&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(state:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): func that produces the next state&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;producen&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== produceN ==&lt;br /&gt;
&lt;br /&gt;
returns a list with numbers from 0..n-1, optionally mapped through a function&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;n&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of elements to produce&lt;br /&gt;
* &#039;&#039;&#039;fn&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(index:int) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): (optional) map function applied to each index &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;paralleln&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== parallelN ==&lt;br /&gt;
&lt;br /&gt;
returns a list with numbers from 0..n-1 mapped in parallel through a function&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;n&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): number of elements to produce&lt;br /&gt;
* &#039;&#039;&#039;fn&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(index:int) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): map function applied to each index in parallel&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;list-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== list? ==&lt;br /&gt;
&lt;br /&gt;
checks if a value is a list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value to check&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;contains&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== contains? ==&lt;br /&gt;
&lt;br /&gt;
checks if a value is in a list; uses the equal?? operator&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list to check&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value to check&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_in ==&lt;br /&gt;
&lt;br /&gt;
tests SQL IN-list membership and returns nil when NULL makes the result UNKNOWN&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;values&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): SQL IN-list values&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value to find&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=JIT_in_Scheme&amp;diff=282</id>
		<title>JIT in Scheme</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=JIT_in_Scheme&amp;diff=282"/>
		<updated>2026-08-27T06:15:13Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot;= JIT Compilation =  Our scheme dialect allows to JIT-compile SCM code into real machine code.   ← Back to Full SCM API documentation  == jit ==  compiles a lambda to optimized native code when this build enables JIT  &amp;#039;&amp;#039;&amp;#039;Allowed number of parameters:&amp;#039;&amp;#039;&amp;#039; 1–1  &amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; === Parameters ===  * &amp;#039;&amp;#039;&amp;#039;fn&amp;#039;&amp;#039;&amp;#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): the function to compile  &amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; === Returns ===  &amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;  &amp;lt;span id=&amp;quot;jit-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt; == jit? ==  tel...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= JIT Compilation =&lt;br /&gt;
&lt;br /&gt;
Our scheme dialect allows to JIT-compile SCM code into real machine code.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
== jit ==&lt;br /&gt;
&lt;br /&gt;
compiles a lambda to optimized native code when this build enables JIT&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;fn&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): the function to compile&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;jit-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== jit? ==&lt;br /&gt;
&lt;br /&gt;
tells whether a value is a JIT-compiled function descriptor&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value to inspect&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== jit-warn-if-fallback ==&lt;br /&gt;
&lt;br /&gt;
prints a diagnostic warning when an enabled JIT build kept a procedure interpreted and returns the procedure unchanged&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;procedure&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): procedure expected to be a native compilation candidate&lt;br /&gt;
* &#039;&#039;&#039;label&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): optional diagnostic label &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;jit-enabled&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== jit-enabled? ==&lt;br /&gt;
&lt;br /&gt;
tells whether this binary was built with the patched Go JIT runtime&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Main_Page&amp;diff=281</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Main_Page&amp;diff=281"/>
		<updated>2026-08-27T06:14:58Z</updated>

		<summary type="html">&lt;p&gt;Carli: /* Scheme documentation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= MemCP – A Modern In-Memory Columnar Database =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:2.5rem 2rem; margin:0 0 1.5rem; border-radius:14px; background:linear-gradient(135deg,#3d6208 0%,#64910c 52%,#76b512 100%); color:#fff; text-align:center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:2.6rem; line-height:1.1; font-weight:700; margin-bottom:.7rem;&amp;quot;&amp;gt;MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.45rem; line-height:1.35; font-weight:600; margin:0 auto .9rem; max-width:56rem;&amp;quot;&amp;gt;A fast, compressed, MySQL-compatible columnar database for modern OLTP and OLAP workloads&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.05rem; line-height:1.6; margin:0 auto 1.4rem; max-width:54rem;&amp;quot;&amp;gt;MemCP combines persistent in-memory operation, adaptive column compression, parallel query execution and direct application APIs in a lightweight database written in Go.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-bottom:1.5rem;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;Beta&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;Open Source&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;MySQL Protocol + HTTP APIs&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;plainlinks&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[[Install MemCP with Docker|&amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border-radius:6px; background:#fff; color:#496f0c; font-weight:700;&amp;quot;&amp;gt;Get started with Docker&amp;lt;/span&amp;gt;]]&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[[Supported SQL|&amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border:1px solid #fff; border-radius:6px; color:#fff; font-weight:700;&amp;quot;&amp;gt;Explore SQL support&amp;lt;/span&amp;gt;]]&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[https://github.com/launix-de/memcp &amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border:1px solid #fff; border-radius:6px; color:#fff; font-weight:700;&amp;quot;&amp;gt;View on GitHub&amp;lt;/span&amp;gt;]&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Memcp-Load.png|center|frameless|1000px|alt=MemCP database dashboard and workload overview]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.85rem 1rem; margin:1rem 0 2rem; border-left:5px solid #d99b00; background:#fff7d6; color:#332600;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Development status: Beta.&#039;&#039;&#039; MemCP is under active development. Check [[Supported SQL]], [[Current Status and Open Issues]] and the durability requirements of your workload before migrating production data.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Choose your path ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:1rem; margin:1rem 0 2rem;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Evaluate MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
Understand the workload model, current status, hardware needs and differences from MySQL.&lt;br /&gt;
&lt;br /&gt;
[[What is OLTP and OLAP|OLTP and OLAP]] · [[Comparison: MemCP vs. MySQL|Compare with MySQL]] · [[Hardware Requirements|Hardware requirements]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Build an application&amp;lt;/div&amp;gt;&lt;br /&gt;
Use the MySQL protocol, SQL over HTTP, RDF or application-specific endpoints inside MemCP.&lt;br /&gt;
&lt;br /&gt;
[[Advanced SQL Tutorial|SQL tutorial]] · [[SQL over REST|SQL over HTTP]] · [[Database Tools compatibility with MemCP|Client tooling]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Operate MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
Plan deployment, migration, persistence, storage backends, settings and performance measurement.&lt;br /&gt;
&lt;br /&gt;
[[Deployment]] · [[Persistency and Performance Guarantees|Durability]] · [[Migration from MySQL and PostgreSQL|Migration]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Understand and contribute&amp;lt;/div&amp;gt;&lt;br /&gt;
Explore the storage engine, optimizer, embedded Scheme runtime and project internals.&lt;br /&gt;
&lt;br /&gt;
[[Query Planner and Physical Lowering|Query planner]] · [[Columnar Storage]] · [[Contributing]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
=== Run with Docker ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run --name memcp \&lt;br /&gt;
  -e ROOT_PASSWORD=&#039;choose-a-password&#039; \&lt;br /&gt;
  -p 4321:4321 -p 3307:3307 \&lt;br /&gt;
  carli2/memcp:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then open &amp;lt;code&amp;gt;http://localhost:4321&amp;lt;/code&amp;gt; and connect a MySQL application to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on port &#039;&#039;&#039;3307&#039;&#039;&#039;. Add a volume mounted at &amp;lt;code&amp;gt;/data&amp;lt;/code&amp;gt; when the container must retain persistent data. See [[Install MemCP with Docker|the complete Docker guide]] before deploying it as a service.&lt;br /&gt;
&lt;br /&gt;
=== Build from source ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://github.com/launix-de/memcp&lt;br /&gt;
cd memcp&lt;br /&gt;
go mod download&lt;br /&gt;
make&lt;br /&gt;
./memcp --api-port=4321 --mysql-port=3307 lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connect with MySQL tooling:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 127.0.0.1 -u root -p -P 3307&lt;br /&gt;
# Enter the password selected for this data directory.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The development default for a fresh data directory is &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt;. Change it before exposing MemCP to another machine. MemCP can also be supervised with PM2:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pm2 start ./memcp --name memcp -- \&lt;br /&gt;
  --no-repl -data ./data --api-port=4321 --mysql-port=3307 lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Background deployments must use &amp;lt;code&amp;gt;--no-repl&amp;lt;/code&amp;gt; so that closing standard input does not terminate the interactive console and stop the server. See [[Compile MemCP from Source|Build from Source]], [[Deployment]] and [[MemCP Console]].&lt;br /&gt;
&lt;br /&gt;
== Key features ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:.8rem; margin:1rem 0;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;High performance&#039;&#039;&#039;&amp;lt;br /&amp;gt;NUMA-aware, parallelized query execution is optimized for multicore CPUs, large caches and NVMe SSDs, serving both OLTP and OLAP workloads.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Columnar storage&#039;&#039;&#039;&amp;lt;br /&amp;gt;Data is stored by column for improved compression, a smaller memory footprint and fast analytical access.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Persistent in-memory operation&#039;&#039;&#039;&amp;lt;br /&amp;gt;MemCP is designed to keep active data in memory while offering configurable per-table durability and persistence backends.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Built-in APIs&#039;&#039;&#039;&amp;lt;br /&amp;gt;SQL over HTTP and in-database services can remove an extra middleware hop for suitable applications.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Adaptive compression&#039;&#039;&#039;&amp;lt;br /&amp;gt;Bit-packing, dictionary encoding and sequence compression can reduce suitable datasets by up to 80% compared with their MySQL/MariaDB representation.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Simple deployment&#039;&#039;&#039;&amp;lt;br /&amp;gt;Start with Docker, PM2 or the native binary. The compact application has historically had an installation footprint of approximately 10 MB.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Extensible frontends&#039;&#039;&#039;&amp;lt;br /&amp;gt;The Go storage engine and embedded Scheme environment support SQL, RDF, REST and custom application interfaces.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #9ad32d; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Cost-based query execution&#039;&#039;&#039;&amp;lt;br /&amp;gt;Logical decorrelation and join optimization are separated from cost-based physical selection of scans, indexes, RecSets, reusable caches and execution pipelines.&amp;lt;br /&amp;gt;[[Query Planner and Physical Lowering|How MemCP plans and lowers queries →]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why MemCP? ==&lt;br /&gt;
&lt;br /&gt;
Traditional relational databases were designed around spinning disks and comparatively small numbers of CPU cores. MemCP rethinks storage and query execution for modern multicore systems, large caches, fast storage and mixed workloads.&lt;br /&gt;
&lt;br /&gt;
Typical use cases include:&lt;br /&gt;
&lt;br /&gt;
* real-time dashboards and analytics;&lt;br /&gt;
* data-heavy SaaS platforms;&lt;br /&gt;
* embedded systems with limited resources;&lt;br /&gt;
* high-throughput OLTP/OLAP hybrids.&lt;br /&gt;
&lt;br /&gt;
Whether MemCP is a good fit depends on the required SQL compatibility, durability, query mix, data size and operational environment. Review [[Supported SQL]], [[Persistency and Performance Guarantees]] and [[Performance Measurement]] rather than treating benchmark figures as universal guarantees.&lt;br /&gt;
&lt;br /&gt;
== MemCP vs. MySQL ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
! Feature&lt;br /&gt;
! MySQL&lt;br /&gt;
! MemCP&lt;br /&gt;
|-&lt;br /&gt;
| Storage model&lt;br /&gt;
| Primarily row-based&lt;br /&gt;
| Column-based and compressed&lt;br /&gt;
|-&lt;br /&gt;
| Performance focus&lt;br /&gt;
| General-purpose relational workloads&lt;br /&gt;
| NUMA-aware, in-memory execution for mixed operational and analytical workloads&lt;br /&gt;
|-&lt;br /&gt;
| In-memory capability&lt;br /&gt;
| Available through selected engines and caching&lt;br /&gt;
| Central design goal and default operating model&lt;br /&gt;
|-&lt;br /&gt;
| REST API integration&lt;br /&gt;
| Normally external&lt;br /&gt;
| Built in&lt;br /&gt;
|-&lt;br /&gt;
| Installation footprint&lt;br /&gt;
| Common server installations are approximately 150 MB or larger&lt;br /&gt;
| The native application has historically been approximately 10 MB&lt;br /&gt;
|-&lt;br /&gt;
| Open source&lt;br /&gt;
| ✅&lt;br /&gt;
| ✅&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
MemCP provides MySQL protocol compatibility but does not claim to implement every MySQL feature. See [[Comparison: MemCP vs. MySQL]] for a detailed comparison and [[Database Tools compatibility with MemCP]] for client compatibility.&lt;br /&gt;
&lt;br /&gt;
== Architecture overview ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tables, schemas and columns&#039;&#039;&#039;: Familiar SQL structures use a compressed columnar physical layout. See [[Databases, Tables and Columns]] and [[Columnar Storage]].&lt;br /&gt;
* &#039;&#039;&#039;Transaction model&#039;&#039;&#039;: Delta and main storage support mixed OLTP and OLAP semantics. See [[Transactions and Isolation]] and [[Shards, RecordIDs, Main Storage, Delta Storage]].&lt;br /&gt;
* &#039;&#039;&#039;Query planning&#039;&#039;&#039;: Logical optimization is separated from physical execution decisions. See [[Query Planner and Physical Lowering]].&lt;br /&gt;
* &#039;&#039;&#039;Persistence&#039;&#039;&#039;: Per-table durability can use filesystem, S3 or Ceph/RADOS storage. See [[Persistency and Performance Guarantees]].&lt;br /&gt;
* &#039;&#039;&#039;Frontends&#039;&#039;&#039;: MemCP provides multiple query and application interfaces:&lt;br /&gt;
** SQL through the MySQL wire protocol and SQL over HTTP;&lt;br /&gt;
** an RDF/graph query frontend;&lt;br /&gt;
** custom APIs through in-database web applications.&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
The following navigation remains on the start page so users and search engines can reach every major documentation area directly.&lt;br /&gt;
&lt;br /&gt;
=== Introduction and evaluation ===&lt;br /&gt;
&lt;br /&gt;
* [[What is OLTP and OLAP]]&lt;br /&gt;
* [[History of the MemCP project]]&lt;br /&gt;
* [[Hardware Requirements]]&lt;br /&gt;
* [[Persistency and Performance Guarantees]]&lt;br /&gt;
* [[Current Status and Open Issues]]&lt;br /&gt;
* [[Comparison: MemCP vs. MySQL]]&lt;br /&gt;
&lt;br /&gt;
=== Getting started ===&lt;br /&gt;
&lt;br /&gt;
* [[Install MemCP with Docker|Install with Docker]]&lt;br /&gt;
* [[With Singularity|Install with Singularity/Apptainer]]&lt;br /&gt;
* [[Compile MemCP from Source|Build from Source]]&lt;br /&gt;
* [[Contributing]]&lt;br /&gt;
* [[Introduction to Scheme]]&lt;br /&gt;
* [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
=== Administration ===&lt;br /&gt;
&lt;br /&gt;
* [[Deployment]]&lt;br /&gt;
* [[Migration from MySQL and PostgreSQL]]&lt;br /&gt;
* [[Settings]]&lt;br /&gt;
* [[Process Hibernation]]&lt;br /&gt;
* [[Performance Measurement]]&lt;br /&gt;
* [[MemCP Console]]&lt;br /&gt;
&lt;br /&gt;
=== Frontends ===&lt;br /&gt;
&lt;br /&gt;
==== SQL frontend ====&lt;br /&gt;
&lt;br /&gt;
* [[Supported SQL]]&lt;br /&gt;
* [[Advanced SQL Tutorial]]&lt;br /&gt;
* [[SQL over REST]]&lt;br /&gt;
* [[Database Tools compatibility with MemCP|Supported Tooling]]&lt;br /&gt;
* [[How SQL Operators are implemented on MemCP]]&lt;br /&gt;
* [[Add custom SQL operators to MemCP]]&lt;br /&gt;
&lt;br /&gt;
==== RDF frontend ====&lt;br /&gt;
&lt;br /&gt;
* [[Introduction to RDF]]&lt;br /&gt;
* [[Advanced Graph Querying]]&lt;br /&gt;
* [[RDF templating and model driven development]]&lt;br /&gt;
&lt;br /&gt;
==== Custom frontends ====&lt;br /&gt;
&lt;br /&gt;
* [[In-Database WebApps|In-Database WebApps and REST Services]]&lt;br /&gt;
* [[MemCP for Microservices]]&lt;br /&gt;
* [[Websockets in MemCP]]&lt;br /&gt;
&lt;br /&gt;
=== Persistence backends and storage ===&lt;br /&gt;
&lt;br /&gt;
* [[File System]]&lt;br /&gt;
* [[S3 Buckets]]&lt;br /&gt;
* [[Ceph/Rados]]&lt;br /&gt;
* [[Cluster Monitor]]&lt;br /&gt;
&lt;br /&gt;
=== Internals ===&lt;br /&gt;
&lt;br /&gt;
==== How MemCP works ====&lt;br /&gt;
&lt;br /&gt;
* [[Databases, Tables and Columns]]&lt;br /&gt;
* [[Shards, RecordIDs, Main Storage, Delta Storage]]&lt;br /&gt;
* [[Columnar Storage]]&lt;br /&gt;
* [[Transactions and Isolation]]&lt;br /&gt;
* [[Query Planner and Physical Lowering]]&lt;br /&gt;
* [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
==== Scheme documentation ====&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
* [[JIT in Scheme|JIT]]&lt;br /&gt;
&lt;br /&gt;
==== Optimizations ====&lt;br /&gt;
&lt;br /&gt;
* [[Query Planner and Physical Lowering]]&lt;br /&gt;
* [[In-Memory Compression, Columnar Compression Techniques]]&lt;br /&gt;
* [[Temporary Columns]]&lt;br /&gt;
* [[Data Auto Sharding and Auto Indexing]]&lt;br /&gt;
* [[Parallel Computing]]&lt;br /&gt;
&lt;br /&gt;
== Further reading ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/launix-de/memcp MemCP on GitHub]&lt;br /&gt;
* [https://www.vldb.org/pvldb/vol13/p2649-boncz.pdf VLDB Research Paper]&lt;br /&gt;
* [https://cs.emis.de/LNI/Proceedings/Proceedings241/383.pdf LNI Proceedings Paper]&lt;br /&gt;
* [https://www.dcs.bbk.ac.uk/~dell/teaching/cc/paper/sigmod10/p135-malewicz.pdf Large Graph Algorithms]&lt;br /&gt;
&lt;br /&gt;
Additional blog posts on design decisions, compression techniques and performance optimization are available on the [https://launix.de/launix/ Launix blog].&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
&lt;br /&gt;
MemCP is an open-source project maintained by developers for developers. Contributions are welcome in the form of bug reports, feature requests and pull requests.&lt;br /&gt;
&lt;br /&gt;
See [[Contributing]] and the [https://github.com/launix-de/memcp GitHub repository].&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Full_SCM_API_documentation&amp;diff=280</id>
		<title>Full SCM API documentation</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Full_SCM_API_documentation&amp;diff=280"/>
		<updated>2026-08-27T06:13:34Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Documentation =&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
* [[JIT in Scheme|JIT]]&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=IO&amp;diff=279</id>
		<title>IO</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=IO&amp;diff=279"/>
		<updated>2026-08-27T06:12:23Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= IO =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;IO&#039;&#039;&#039; module provides functions for input and output operations, environment handling, file streaming, server control, and argument parsing in SCM.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
== print ==&lt;br /&gt;
&lt;br /&gt;
Prints values to stdout (only in IO environment)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): values to print &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== env ==&lt;br /&gt;
&lt;br /&gt;
returns the content of a environment variable&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;var&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): envvar&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): default if the env is not found &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== help ==&lt;br /&gt;
&lt;br /&gt;
Lists all functions or returns help for a specific function as a string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;topic&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): function to get help about &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== import ==&lt;br /&gt;
&lt;br /&gt;
Imports a file .scm file into current namespace&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;filename&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): filename relative to folder of source file or absolute path&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== load ==&lt;br /&gt;
&lt;br /&gt;
Loads a file or stream and returns the string or iterates line-wise&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;filenameOrStream&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|stream&amp;lt;/code&amp;gt;): filename relative to folder of source file, absolute path, or stream to read from&lt;br /&gt;
* &#039;&#039;&#039;linehandler&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(line:string) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): handler that reads each line; each line may end with delimiter &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
* &#039;&#039;&#039;delimiter&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): delimiter to extract; if no delimiter is given, the file is read as whole and returned or passed to linehandler &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string|bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== stream ==&lt;br /&gt;
&lt;br /&gt;
Opens a file readonly as stream&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;filename&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): filename relative to folder of source file or absolute path&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;stream&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== watch ==&lt;br /&gt;
&lt;br /&gt;
Loads a file and calls the callback. Whenever the file changes on disk, the file is load again.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;filename&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): filename relative to folder of source file or absolute path&lt;br /&gt;
* &#039;&#039;&#039;updatehandler&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(content:string) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): handler that receives the file content func(content)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== serve ==&lt;br /&gt;
&lt;br /&gt;
Opens a HTTP server at a given port&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;port&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): port number for HTTP server&lt;br /&gt;
* &#039;&#039;&#039;handler&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(req:any, res:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): handler: lambda(req res) that handles the http request&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;servestatic&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== serveStatic ==&lt;br /&gt;
&lt;br /&gt;
creates a static handler for use as a callback in (serve) - returns a handler lambda(req res)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;directory&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): folder with the files to serve&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func(req:any, res:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== mysql ==&lt;br /&gt;
&lt;br /&gt;
Imports a file .scm file into current namespace&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;port&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): port number for MySQL server&lt;br /&gt;
* &#039;&#039;&#039;getPassword&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(username:string) -&amp;amp;gt; string|nil&amp;lt;/code&amp;gt;): lambda(username string) string|nil has to return the password for a user or nil to deny login&lt;br /&gt;
* &#039;&#039;&#039;schemacallback&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(username:string, schema:string) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): lambda(username schema) bool handler check whether user is allowed to schema - you should check access rights here&lt;br /&gt;
* &#039;&#039;&#039;handler&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(schema:string, sql:string, resultrow:func, session:func) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): lambda(schema sql resultrow session) handler to process sql query in schema. resultrow is a lambda(list)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== mysql_socket ==&lt;br /&gt;
&lt;br /&gt;
Listen on a Unix domain socket for MySQL protocol&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 4–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;socketpath&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): path to the Unix domain socket&lt;br /&gt;
* &#039;&#039;&#039;getPassword&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(username:string) -&amp;amp;gt; string|nil&amp;lt;/code&amp;gt;): lambda(username string) string|nil has to return the password for a user or nil to deny login&lt;br /&gt;
* &#039;&#039;&#039;schemacallback&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(username:string, schema:string) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): lambda(username schema) bool handler check whether user is allowed to schema - you should check access rights here&lt;br /&gt;
* &#039;&#039;&#039;handler&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(schema:string, sql:string, resultrow:func, session:func) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): lambda(schema sql resultrow session) handler to process sql query in schema. resultrow is a lambda(list)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== password ==&lt;br /&gt;
&lt;br /&gt;
Hashes a password with sha1 (for mysql user authentication)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;password&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): plain text password to hash&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== shutdown ==&lt;br /&gt;
&lt;br /&gt;
Initiates a graceful shutdown of memcp after a short delay&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== crash ==&lt;br /&gt;
&lt;br /&gt;
Hard process exit with no cleanup (kill -9 equivalent) for crash testing. SCM only, not exposed to SQL.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== path ==&lt;br /&gt;
&lt;br /&gt;
Joins path segments using the OS path separator and cleans the result&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;segments&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): path segments to join &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== args ==&lt;br /&gt;
&lt;br /&gt;
Returns command line arguments&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== arg ==&lt;br /&gt;
&lt;br /&gt;
Gets a command line argument value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;longname&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): long argument name (without --)&lt;br /&gt;
* &#039;&#039;&#039;shortname&#039;&#039;&#039; (&amp;lt;code&amp;gt;string|any&amp;lt;/code&amp;gt;): short argument name (without -) or default value if only 2 args&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): default value if argument not found &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Date&amp;diff=278</id>
		<title>Date</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Date&amp;diff=278"/>
		<updated>2026-08-27T06:11:21Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Date =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Date&#039;&#039;&#039; module provides date and time functionality for the SCM programming language. This module includes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Current time&#039;&#039;&#039;: Functions to get the current Unix timestamp (now)&lt;br /&gt;
* &#039;&#039;&#039;Date parsing&#039;&#039;&#039;: Functions to parse date strings into Unix timestamps (parse_date)&lt;br /&gt;
&lt;br /&gt;
These functions provide essential tools for working with dates and timestamps in SCM programs, enabling time-based operations and date string processing.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== sql_temporal_output ==&lt;br /&gt;
&lt;br /&gt;
formats a temporal SQL result according to its compiler-tracked declared type&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): type-flexible temporal value&lt;br /&gt;
* &#039;&#039;&#039;sql_type&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): declared SQL temporal type&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== now ==&lt;br /&gt;
&lt;br /&gt;
returns the current date/time&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== nanotime ==&lt;br /&gt;
&lt;br /&gt;
returns a monotonic nanosecond timestamp for benchmarking (not wall-clock)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== current_date ==&lt;br /&gt;
&lt;br /&gt;
returns the current date (midnight in session timezone)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== parse_date ==&lt;br /&gt;
&lt;br /&gt;
parses a date from a string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): values to parse&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== format_date ==&lt;br /&gt;
&lt;br /&gt;
formats a unix timestamp, date, or datetime string into a date string&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;timestamp&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): unix timestamp, date, or datetime string&lt;br /&gt;
* &#039;&#039;&#039;format&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): MySQL-style format string (e.g. %Y-%m-%d %H:%i:%s)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== extract_date ==&lt;br /&gt;
&lt;br /&gt;
extracts a date field (YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, QUARTER, WEEK, DAYOFWEEK, WEEKDAY) from a date value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): date value&lt;br /&gt;
* &#039;&#039;&#039;field&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): field name: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, QUARTER, WEEK, DAYOFWEEK, WEEKDAY&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== date_add ==&lt;br /&gt;
&lt;br /&gt;
adds an interval to a date value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): date value&lt;br /&gt;
* &#039;&#039;&#039;amount&#039;&#039;&#039; (&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;): interval amount&lt;br /&gt;
* &#039;&#039;&#039;unit&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): interval unit: DAY, WEEK, MONTH, YEAR, HOUR, MINUTE, SECOND&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== date_sub ==&lt;br /&gt;
&lt;br /&gt;
subtracts an interval from a date value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): date value&lt;br /&gt;
* &#039;&#039;&#039;amount&#039;&#039;&#039; (&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;): interval amount&lt;br /&gt;
* &#039;&#039;&#039;unit&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): interval unit: DAY, WEEK, MONTH, YEAR, HOUR, MINUTE, SECOND&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== date_trunc_day ==&lt;br /&gt;
&lt;br /&gt;
truncates a datetime to date (midnight UTC)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): date/datetime value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== timestampdiff ==&lt;br /&gt;
&lt;br /&gt;
returns the difference between two datetimes in the given unit&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;unit&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, YEAR&lt;br /&gt;
* &#039;&#039;&#039;dt1&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first datetime&lt;br /&gt;
* &#039;&#039;&#039;dt2&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second datetime&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== datediff ==&lt;br /&gt;
&lt;br /&gt;
returns number of days between two dates (date1 - date2)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;date1&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first date&lt;br /&gt;
* &#039;&#039;&#039;date2&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second date&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== str_to_date ==&lt;br /&gt;
&lt;br /&gt;
parses a string with MySQL format specifiers to a date&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): date string&lt;br /&gt;
* &#039;&#039;&#039;format&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): MySQL format string (e.g. %Y-%m-%d)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;date&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Associative_Lists_/_Dictionaries&amp;diff=277</id>
		<title>Associative Lists / Dictionaries</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Associative_Lists_/_Dictionaries&amp;diff=277"/>
		<updated>2026-08-27T06:10:09Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Associative Lists / Dictionaries =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Associative Lists / Dictionaries&#039;&#039;&#039; module provides key-value data structure operations for the SCM programming language. This module includes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Dictionary filtering&#039;&#039;&#039;: Functions to filter dictionaries based on key-value conditions (filter_assoc)&lt;br /&gt;
* &#039;&#039;&#039;Dictionary mapping&#039;&#039;&#039;: Transform dictionary values while preserving keys (map_assoc)&lt;br /&gt;
* &#039;&#039;&#039;Dictionary reduction&#039;&#039;&#039;: Aggregate dictionary data into single values (reduce_assoc)&lt;br /&gt;
* &#039;&#039;&#039;Dictionary queries&#039;&#039;&#039;: Check for key existence and extract data (has_assoc?, extract_assoc)&lt;br /&gt;
* &#039;&#039;&#039;Dictionary modification&#039;&#039;&#039;: Set individual values and merge dictionaries (set_assoc, merge_assoc)&lt;br /&gt;
&lt;br /&gt;
These functions provide essential tools for working with associative data structures, enabling efficient key-value operations and dictionary manipulation in SCM programs.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
== filter_assoc ==&lt;br /&gt;
&lt;br /&gt;
returns a filtered dictionary according to a filter function&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dict&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): dictionary that has to be filtered&lt;br /&gt;
* &#039;&#039;&#039;condition&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(key:string, value:any) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): filter function func(string any)-&amp;amp;gt;bool where the first parameter is the key, the second is the value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== find_assoc ==&lt;br /&gt;
&lt;br /&gt;
returns the first key/value pair that passes the condition function, or nil/default if none matches&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dict&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): dictionary to search&lt;br /&gt;
* &#039;&#039;&#039;condition&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(key:string, value:any) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;): predicate func(string any)-&amp;amp;gt;bool that is applied until the first match&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): optional default value if nothing matches &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== map_assoc ==&lt;br /&gt;
&lt;br /&gt;
returns a mapped dictionary according to a map function Keys will stay the same but values are mapped.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dict&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): dictionary that has to be mapped&lt;br /&gt;
* &#039;&#039;&#039;map&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(key:string, value:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): map function func(string any)-&amp;amp;gt;any where the first parameter is the key, the second is the value. It must return the new value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== reduce_assoc ==&lt;br /&gt;
&lt;br /&gt;
reduces a dictionary according to a reduce function&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dict&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): dictionary that has to be reduced&lt;br /&gt;
* &#039;&#039;&#039;reduce&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(acc:any, key:any, value:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): reduce function func(any string any)-&amp;amp;gt;any where the first parameter is the accumulator, second is key, third is value. It must return the new accumulator.&lt;br /&gt;
* &#039;&#039;&#039;neutral&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): initial value for the accumulator&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== make_structural_index ==&lt;br /&gt;
&lt;br /&gt;
Builds an immutable structural-expression index. It eagerly hashes every key and every node under roots, then returns a parallel-safe lookup function that maps an equal expression to its zero-based key position or nil.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;keys&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): immutable structural expressions to index&lt;br /&gt;
* &#039;&#039;&#039;roots&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): immutable expression roots whose descendant hashes are precomputed&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func(expression:any) -&amp;amp;gt; int|nil&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== make_structural_catalog ==&lt;br /&gt;
&lt;br /&gt;
Creates an atomic compile-local structural catalog. Look up with (catalog key), insert with (catalog key value), or freeze with (catalog) for parallel-safe read-only lookup.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;mode&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool|symbol&amp;lt;/code&amp;gt;): true forces collisions for tests; ast selects type-stable compiler equality &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;func&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;has_assoc&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== has_assoc? ==&lt;br /&gt;
&lt;br /&gt;
checks if a dictionary has a key present&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dict&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): dictionary that has to be checked&lt;br /&gt;
* &#039;&#039;&#039;key&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): key to test&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== get_assoc ==&lt;br /&gt;
&lt;br /&gt;
gets a value from a dictionary by key, returns nil if not found&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dict&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): dictionary to look up&lt;br /&gt;
* &#039;&#039;&#039;key&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): key to look up&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): optional default value if key not found &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== get_assoc_pairlist ==&lt;br /&gt;
&lt;br /&gt;
gets a value from a list of key/value rows without flattening the rows&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;rows&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): list whose rows contain a key followed by one or more values&lt;br /&gt;
* &#039;&#039;&#039;key&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): key compared with the first item of each row&lt;br /&gt;
* &#039;&#039;&#039;default&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value returned when no row contains the key&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== extract_assoc ==&lt;br /&gt;
&lt;br /&gt;
applies a function (key value) on the dictionary and returns the results as a flat list&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dict&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): dictionary that has to be checked&lt;br /&gt;
* &#039;&#039;&#039;map&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(key:string, value:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): func(key, value)-&amp;amp;gt;any that extracts one element per key-value pair&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== set_assoc ==&lt;br /&gt;
&lt;br /&gt;
returns a new dictionary where a single value has been changed. The original dictionary is not modified.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–4&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dict&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): input dictionary&lt;br /&gt;
* &#039;&#039;&#039;key&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): key that has to be set&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): new value to set&lt;br /&gt;
* &#039;&#039;&#039;merge&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(old:any, new:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): (optional) func(any any)-&amp;amp;gt;any that is called when a value is overwritten. The first parameter is the old value, the second is the new value. It must return the merged value that shall be physically stored in the new dictionary. &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== merge_assoc ==&lt;br /&gt;
&lt;br /&gt;
returns a dictionary where all keys from dict1 and all keys from dict2 are present. If a key is present in both inputs, the second one will be dominant so the first value will be overwritten unless you provide a merge function&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dict1&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): first input dictionary that has to be changed. You must not use this value again.&lt;br /&gt;
* &#039;&#039;&#039;dict2&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): input dictionary that contains the new values that have to be added&lt;br /&gt;
* &#039;&#039;&#039;merge&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(old:any, new:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): (optional) func(any any)-&amp;amp;gt;any that is called when a value is overwritten. The first parameter is the old value, the second is the new value from dict2. It must return the merged value that shall be pysically stored in the new dictionary. &#039;&#039;(optional)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sort ==&lt;br /&gt;
&lt;br /&gt;
returns a sorted copy of a list using a comparator (lambda (a b) truthy/falsy)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;comparator&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(any, any) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sort_mut ==&lt;br /&gt;
&lt;br /&gt;
sorts a list in-place using a comparator (lambda (a b) truthy/falsy)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;list&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;):&lt;br /&gt;
* &#039;&#039;&#039;comparator&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(any, any) -&amp;amp;gt; bool&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== mapkey_assoc ==&lt;br /&gt;
&lt;br /&gt;
returns a mapped dictionary according to a map function Values stay the same but keys are mapped.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;dict&#039;&#039;&#039; (&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;): dictionary whose keys have to be mapped&lt;br /&gt;
* &#039;&#039;&#039;map&#039;&#039;&#039; (&amp;lt;code&amp;gt;func(key:string, value:any) -&amp;amp;gt; any&amp;lt;/code&amp;gt;): map function func(key, value)-&amp;amp;gt;key where the first parameter is the old key, the second is the value. It must return the new key.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Arithmetic_/_Logic&amp;diff=276</id>
		<title>Arithmetic / Logic</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Arithmetic_/_Logic&amp;diff=276"/>
		<updated>2026-08-27T06:09:39Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Arithmetic / Logic =&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;Arithmetic / Logic&#039;&#039;&#039; module provides essential mathematical operations and logical comparisons for the SCM programming language. This module includes:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Type checking&#039;&#039;&#039;: Functions to verify data types (int?, number?, nil?)&lt;br /&gt;
* &#039;&#039;&#039;Basic arithmetic&#039;&#039;&#039;: Addition (+), subtraction (-), multiplication (*), and division (/)&lt;br /&gt;
* &#039;&#039;&#039;Comparison operations&#039;&#039;&#039;: All standard comparison operators (&amp;gt;, &amp;lt;, &amp;gt;=, &amp;lt;=, equal?)&lt;br /&gt;
* &#039;&#039;&#039;Logical operations&#039;&#039;&#039;: Boolean negation (!, not) and advanced equality checks&lt;br /&gt;
* &#039;&#039;&#039;Mathematical functions&#039;&#039;&#039;: Min/max operations and rounding functions (floor, ceil, round)&lt;br /&gt;
&lt;br /&gt;
These functions form the mathematical foundation for calculations and logical decision-making in SCM programs.&lt;br /&gt;
&lt;br /&gt;
← Back to [[Full SCM API documentation]]&lt;br /&gt;
&amp;lt;span id=&amp;quot;int&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== int? ==&lt;br /&gt;
&lt;br /&gt;
tells if the value is a integer&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;number&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== number? ==&lt;br /&gt;
&lt;br /&gt;
tells if the value is a number&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;symbol&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== symbol? ==&lt;br /&gt;
&lt;br /&gt;
tells if the value is a symbol&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== + ==&lt;br /&gt;
&lt;br /&gt;
adds two or more numbers&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): values to add &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_sum_reduce ==&lt;br /&gt;
&lt;br /&gt;
adds two SQL SUM values while treating NULL as the empty aggregate identity&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;left&#039;&#039;&#039; (&amp;lt;code&amp;gt;number|nil&amp;lt;/code&amp;gt;): partial sum&lt;br /&gt;
* &#039;&#039;&#039;right&#039;&#039;&#039; (&amp;lt;code&amp;gt;number|nil&amp;lt;/code&amp;gt;): next value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number|nil&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== - ==&lt;br /&gt;
&lt;br /&gt;
subtracts two or more numbers from the first one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): values &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_add_numeric_literals ==&lt;br /&gt;
&lt;br /&gt;
adds two SQL numeric literals using their exact decimal spellings&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): left literal&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): right literal&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_sub_numeric_literals ==&lt;br /&gt;
&lt;br /&gt;
subtracts two SQL numeric literals using their exact decimal spellings&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): left literal&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): right literal&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== * ==&lt;br /&gt;
&lt;br /&gt;
multiplies two or more numbers&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): values &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== / ==&lt;br /&gt;
&lt;br /&gt;
divides two or more numbers from the first one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): values &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== mod ==&lt;br /&gt;
&lt;br /&gt;
returns the remainder of integer division (modulo)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): dividend&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): divisor&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== &amp;amp;lt;= ==&lt;br /&gt;
&lt;br /&gt;
compares two numbers or strings; returns nil if either value is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== &amp;amp;lt; ==&lt;br /&gt;
&lt;br /&gt;
compares two numbers or strings; returns nil if either value is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== &amp;amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
compares two numbers or strings; returns nil if either value is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== &amp;amp;gt;= ==&lt;br /&gt;
&lt;br /&gt;
compares two numbers or strings; returns nil if either value is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;equal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== equal? ==&lt;br /&gt;
&lt;br /&gt;
compares two values of the same type, (equal? nil nil) is true&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;equal-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== equal?? ==&lt;br /&gt;
&lt;br /&gt;
performs a SQL compliant sloppy equality check on primitive values (number, int, string, bool. nil), strings are compared case insensitive, (equal? nil nil) is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_not ==&lt;br /&gt;
&lt;br /&gt;
negates a SQL predicate while preserving nil as UNKNOWN&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): SQL predicate value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool|nil&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== equal_collate ==&lt;br /&gt;
&lt;br /&gt;
performs SQL equality with a specified collation (e.g. *_ci case-insensitive, *_bin case-sensitive); returns nil if either arg is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): left side&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): right side&lt;br /&gt;
* &#039;&#039;&#039;collation&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): collation name&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== notequal_collate ==&lt;br /&gt;
&lt;br /&gt;
performs SQL inequality with a specified collation; returns nil if either arg is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): left side&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): right side&lt;br /&gt;
* &#039;&#039;&#039;collation&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): collation name&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== ! ==&lt;br /&gt;
&lt;br /&gt;
negates the boolean value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== not ==&lt;br /&gt;
&lt;br /&gt;
negates the boolean value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;nil&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== nil? ==&lt;br /&gt;
&lt;br /&gt;
returns true if value is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== min ==&lt;br /&gt;
&lt;br /&gt;
returns the smallest value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number|string&amp;lt;/code&amp;gt;): value &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number|string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== max ==&lt;br /&gt;
&lt;br /&gt;
returns the highest value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number|string&amp;lt;/code&amp;gt;): value &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number|string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== floor ==&lt;br /&gt;
&lt;br /&gt;
rounds the number down&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil ==&lt;br /&gt;
&lt;br /&gt;
rounds the number up&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== round ==&lt;br /&gt;
&lt;br /&gt;
rounds the number&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_decimal_output ==&lt;br /&gt;
&lt;br /&gt;
normalizes a DECIMAL-derived result to its declared output scale&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-28&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number|nil&amp;lt;/code&amp;gt;): DECIMAL-derived value&lt;br /&gt;
* &#039;&#039;&#039;scale&#039;&#039;&#039; (&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;): declared decimal scale&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-28&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number|nil&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_abs ==&lt;br /&gt;
&lt;br /&gt;
SQL ABS(): returns absolute value, NULL-safe&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-29&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-29&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sqrt ==&lt;br /&gt;
&lt;br /&gt;
returns the square root of a number&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-30&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-30&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_rand ==&lt;br /&gt;
&lt;br /&gt;
SQL RAND(): returns a random float in [0,1)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-31&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-31&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== parameterize_sql_select_literals ==&lt;br /&gt;
&lt;br /&gt;
replaces safe literals in a top-level MySQL SELECT and returns normalized SQL, positional runtime bindings, and its stable shape hash&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-32&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;query&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-32&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Arithmetic_/_Logic&amp;diff=275</id>
		<title>Arithmetic / Logic</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Arithmetic_/_Logic&amp;diff=275"/>
		<updated>2026-08-27T06:08:03Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span id=&amp;quot;arithmetic--logic&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
= Arithmetic / Logic =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;int&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== int? ==&lt;br /&gt;
&lt;br /&gt;
tells if the value is a integer&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;number&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== number? ==&lt;br /&gt;
&lt;br /&gt;
tells if the value is a number&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;symbol&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== symbol? ==&lt;br /&gt;
&lt;br /&gt;
tells if the value is a symbol&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== + ==&lt;br /&gt;
&lt;br /&gt;
adds two or more numbers&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): values to add &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_sum_reduce ==&lt;br /&gt;
&lt;br /&gt;
adds two SQL SUM values while treating NULL as the empty aggregate identity&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;left&#039;&#039;&#039; (&amp;lt;code&amp;gt;number|nil&amp;lt;/code&amp;gt;): partial sum&lt;br /&gt;
* &#039;&#039;&#039;right&#039;&#039;&#039; (&amp;lt;code&amp;gt;number|nil&amp;lt;/code&amp;gt;): next value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number|nil&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== - ==&lt;br /&gt;
&lt;br /&gt;
subtracts two or more numbers from the first one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): values &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_add_numeric_literals ==&lt;br /&gt;
&lt;br /&gt;
adds two SQL numeric literals using their exact decimal spellings&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): left literal&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): right literal&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_sub_numeric_literals ==&lt;br /&gt;
&lt;br /&gt;
subtracts two SQL numeric literals using their exact decimal spellings&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): left literal&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): right literal&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== * ==&lt;br /&gt;
&lt;br /&gt;
multiplies two or more numbers&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): values &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-8&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-2&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== / ==&lt;br /&gt;
&lt;br /&gt;
divides two or more numbers from the first one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): values &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-9&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== mod ==&lt;br /&gt;
&lt;br /&gt;
returns the remainder of integer division (modulo)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): dividend&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): divisor&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-10&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-3&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== &amp;amp;lt;= ==&lt;br /&gt;
&lt;br /&gt;
compares two numbers or strings; returns nil if either value is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-11&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-4&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== &amp;amp;lt; ==&lt;br /&gt;
&lt;br /&gt;
compares two numbers or strings; returns nil if either value is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-12&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-5&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== &amp;amp;gt; ==&lt;br /&gt;
&lt;br /&gt;
compares two numbers or strings; returns nil if either value is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-13&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-6&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== &amp;amp;gt;= ==&lt;br /&gt;
&lt;br /&gt;
compares two numbers or strings; returns nil if either value is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-14&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;equal&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== equal? ==&lt;br /&gt;
&lt;br /&gt;
compares two values of the same type, (equal? nil nil) is true&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-15&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;equal-1&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== equal?? ==&lt;br /&gt;
&lt;br /&gt;
performs a SQL compliant sloppy equality check on primitive values (number, int, string, bool. nil), strings are compared case insensitive, (equal? nil nil) is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): first value&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): second value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-16&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_not ==&lt;br /&gt;
&lt;br /&gt;
negates a SQL predicate while preserving nil as UNKNOWN&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): SQL predicate value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-17&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool|nil&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== equal_collate ==&lt;br /&gt;
&lt;br /&gt;
performs SQL equality with a specified collation (e.g. *_ci case-insensitive, *_bin case-sensitive); returns nil if either arg is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): left side&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): right side&lt;br /&gt;
* &#039;&#039;&#039;collation&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): collation name&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-18&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== notequal_collate ==&lt;br /&gt;
&lt;br /&gt;
performs SQL inequality with a specified collation; returns nil if either arg is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 3–3&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;a&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): left side&lt;br /&gt;
* &#039;&#039;&#039;b&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): right side&lt;br /&gt;
* &#039;&#039;&#039;collation&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;): collation name&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-19&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;-7&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== ! ==&lt;br /&gt;
&lt;br /&gt;
negates the boolean value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-20&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== not ==&lt;br /&gt;
&lt;br /&gt;
negates the boolean value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-21&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;nil&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
== nil? ==&lt;br /&gt;
&lt;br /&gt;
returns true if value is nil&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;any&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-22&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;bool&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== min ==&lt;br /&gt;
&lt;br /&gt;
returns the smallest value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number|string&amp;lt;/code&amp;gt;): value &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-23&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number|string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== max ==&lt;br /&gt;
&lt;br /&gt;
returns the highest value&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–10000&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value...&#039;&#039;&#039; (&amp;lt;code&amp;gt;number|string&amp;lt;/code&amp;gt;): value &#039;&#039;(variadic)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-24&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number|string&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== floor ==&lt;br /&gt;
&lt;br /&gt;
rounds the number down&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-25&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== ceil ==&lt;br /&gt;
&lt;br /&gt;
rounds the number up&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-26&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== round ==&lt;br /&gt;
&lt;br /&gt;
rounds the number&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-27&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_decimal_output ==&lt;br /&gt;
&lt;br /&gt;
normalizes a DECIMAL-derived result to its declared output scale&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 2–2&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-28&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number|nil&amp;lt;/code&amp;gt;): DECIMAL-derived value&lt;br /&gt;
* &#039;&#039;&#039;scale&#039;&#039;&#039; (&amp;lt;code&amp;gt;int&amp;lt;/code&amp;gt;): declared decimal scale&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-28&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number|nil&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_abs ==&lt;br /&gt;
&lt;br /&gt;
SQL ABS(): returns absolute value, NULL-safe&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-29&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-29&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sqrt ==&lt;br /&gt;
&lt;br /&gt;
returns the square root of a number&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-30&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;value&#039;&#039;&#039; (&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;): value&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-30&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== sql_rand ==&lt;br /&gt;
&lt;br /&gt;
SQL RAND(): returns a random float in [0,1)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 0–0&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-31&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This function has no parameters.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-31&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;number&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== parameterize_sql_select_literals ==&lt;br /&gt;
&lt;br /&gt;
replaces safe literals in a top-level MySQL SELECT and returns normalized SQL, positional runtime bindings, and its stable shape hash&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Allowed number of parameters:&#039;&#039;&#039; 1–1&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;parameters-32&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Parameters ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;query&#039;&#039;&#039; (&amp;lt;code&amp;gt;string&amp;lt;/code&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;span id=&amp;quot;returns-32&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
=== Returns ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;list&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Supported_SQL&amp;diff=274</id>
		<title>Supported SQL</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Supported_SQL&amp;diff=274"/>
		<updated>2026-08-26T07:31:35Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Statements ==&lt;br /&gt;
The following SQL statements are supported:&lt;br /&gt;
&lt;br /&gt;
* SELECT FROM GROUP BY HAVING ORDER BY LIMIT OFFSET&lt;br /&gt;
* UPDATE SET WHERE&lt;br /&gt;
* DELETE FROM WHERE&lt;br /&gt;
* INSERT INTO VALUES ON DUPLICATE KEY UPDATE / INSERT ... ON CONFLICT (PostgreSQL)&lt;br /&gt;
* INSERT IGNORE&lt;br /&gt;
* CREATE TABLE&lt;br /&gt;
* ALTER TABLE&lt;br /&gt;
* CREATE DATABASE&lt;br /&gt;
* CREATE USER&lt;br /&gt;
* ALTER USER&lt;br /&gt;
* SHOW DATABASES&lt;br /&gt;
* SHOW TABLES&lt;br /&gt;
* SHOW TABLE STATUS&lt;br /&gt;
* SHOW VARIABLES&lt;br /&gt;
* SET NAMES (no function)&lt;br /&gt;
* DROP DATABASE&lt;br /&gt;
* DROP TABLE&lt;br /&gt;
* SET SESSION&lt;br /&gt;
* LOCK TABLES (no function)&lt;br /&gt;
* UNLOCK TABLES (no function)&lt;br /&gt;
&lt;br /&gt;
== Expressions ==&lt;br /&gt;
The following functions are supported:&lt;br /&gt;
* CASE WHEN THEN ELSE END&lt;br /&gt;
* DATABASE&lt;br /&gt;
* PASSWORD (hashes a password for user authentication)&lt;br /&gt;
* FLOOR&lt;br /&gt;
* CEIL&lt;br /&gt;
* CEILING&lt;br /&gt;
* ROUND&lt;br /&gt;
* UPPER&lt;br /&gt;
* LOWER&lt;br /&gt;
* CAST AS UNSIGNED&lt;br /&gt;
* CAST AS CHAR CHARACTER SET utf8&lt;br /&gt;
* CONCAT&lt;br /&gt;
* COALESCE&lt;br /&gt;
* UNIX_TIMESTAMP&lt;br /&gt;
* LIKE&lt;br /&gt;
* ILIKE&lt;br /&gt;
&lt;br /&gt;
== Aggregates ==&lt;br /&gt;
The following aggregates are available:&lt;br /&gt;
&lt;br /&gt;
* COUNT&lt;br /&gt;
* SUM&lt;br /&gt;
* AVG&lt;br /&gt;
* MIN&lt;br /&gt;
* MAX&lt;br /&gt;
&lt;br /&gt;
== Modifiers ==&lt;br /&gt;
&lt;br /&gt;
* COLLATE&lt;br /&gt;
&lt;br /&gt;
== JSON ==&lt;br /&gt;
JSON support is documented separately in the [[JSON|MemCP MySQL- and Postgres-compatible JSON SQL]]&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=JSON&amp;diff=273</id>
		<title>JSON</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=JSON&amp;diff=273"/>
		<updated>2026-08-26T07:22:04Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot;= JSON and SQL/JSON in MemCP =  &amp;#039;&amp;#039;&amp;#039;MemCP provides native JSON and SQL/JSON support on its high-performance columnar SQL engine.&amp;#039;&amp;#039;&amp;#039; JSON documents can be filtered, joined, grouped, sorted, modified and assembled into deeply nested application responses without leaving SQL.  The same JSON engine is exposed through both MemCP SQL dialects: applications get MySQL/MariaDB-compatible JSON functions such as &amp;lt;code&amp;gt;JSON_EXTRACT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_VALUE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_OBJECT&amp;lt;/...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= JSON and SQL/JSON in MemCP =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP provides native JSON and SQL/JSON support on its high-performance columnar SQL engine.&#039;&#039;&#039; JSON documents can be filtered, joined, grouped, sorted, modified and assembled into deeply nested application responses without leaving SQL.&lt;br /&gt;
&lt;br /&gt;
The same JSON engine is exposed through both MemCP SQL dialects: applications get MySQL/MariaDB-compatible JSON functions such as &amp;lt;code&amp;gt;JSON_EXTRACT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_VALUE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_OBJECT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_ARRAYAGG&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;JSON_TABLE&amp;lt;/code&amp;gt;, as well as PostgreSQL-compatible &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;jsonb&amp;lt;/code&amp;gt; operators, constructors, aggregates and JSONPath functions. This makes it possible to migrate JSON-heavy SQL queries or run MemCP beside an existing MySQL or PostgreSQL application. See [[Migration from MySQL and PostgreSQL]] for connection options and [[Supported SQL]] for the wider SQL feature set.&lt;br /&gt;
&lt;br /&gt;
JSON columns validate incoming documents and convert them to MemCP&#039;s native tagged BSON value. Objects and arrays therefore remain structured while they are filtered, joined, sorted or aggregated; they are serialized to JSON only at the SQL/API boundary.&lt;br /&gt;
&lt;br /&gt;
JSON functions also accept ordinary character strings containing JSON. Such strings are parsed when the function needs a JSON value. Use a &amp;lt;code&amp;gt;JSON&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;JSONB&amp;lt;/code&amp;gt; column for repeatedly queried documents so that parsing happens on write instead of on every read.&lt;br /&gt;
&lt;br /&gt;
== MemCP compared with MySQL JSON, MariaDB JSON and PostgreSQL JSONB ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! SQL dialect&lt;br /&gt;
! Familiar JSON syntax in MemCP&lt;br /&gt;
! Internal representation in MemCP&lt;br /&gt;
! Typical use&lt;br /&gt;
|-&lt;br /&gt;
| MySQL&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_EXTRACT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_VALUE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_TABLE&amp;lt;/code&amp;gt;&lt;br /&gt;
| Native immutable BSON&lt;br /&gt;
| Existing MySQL applications and document columns&lt;br /&gt;
|-&lt;br /&gt;
| MariaDB&lt;br /&gt;
| MySQL-style JSON functions and JSONPath&lt;br /&gt;
| Native immutable BSON instead of LONGTEXT&lt;br /&gt;
| MariaDB-compatible SQL and mixed relational/document workloads&lt;br /&gt;
|-&lt;br /&gt;
| PostgreSQL&lt;br /&gt;
| &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;jsonb&amp;lt;/code&amp;gt; casts, operators, JSONPath and set-returning functions&lt;br /&gt;
| One native BSON representation for both &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;jsonb&amp;lt;/code&amp;gt;&lt;br /&gt;
| PostgreSQL JSONB queries, containment and relational projection&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Unlike a database that reparses a text document for every JSON expression, a declared MemCP &amp;lt;code&amp;gt;JSON&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;JSONB&amp;lt;/code&amp;gt; column is converted when it is written. Frequently used paths can participate in deterministic computed expressions and computed indexes.&lt;br /&gt;
&lt;br /&gt;
== Quick start ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
CREATE TABLE events (&lt;br /&gt;
	id INT PRIMARY KEY,&lt;br /&gt;
	category VARCHAR(40),&lt;br /&gt;
	payload JSON,&lt;br /&gt;
	created_at DATETIME&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
INSERT INTO events VALUES&lt;br /&gt;
	(1, &#039;customer&#039;, &#039;{&amp;quot;customer&amp;quot;:{&amp;quot;name&amp;quot;:&amp;quot;Ada&amp;quot;,&amp;quot;rank&amp;quot;:2},&amp;quot;tags&amp;quot;:[&amp;quot;sql&amp;quot;,&amp;quot;go&amp;quot;]}&#039;, NOW());&lt;br /&gt;
&lt;br /&gt;
SELECT&lt;br /&gt;
	id,&lt;br /&gt;
	JSON_VALUE(payload, &#039;$.customer.name&#039;) AS customer,&lt;br /&gt;
	JSON_EXTRACT(payload, &#039;$.customer.rank&#039;) + 1 AS next_rank&lt;br /&gt;
FROM events&lt;br /&gt;
WHERE JSON_CONTAINS(payload, &#039;&amp;quot;sql&amp;quot;&#039;, &#039;$.tags&#039;)&lt;br /&gt;
ORDER BY JSON_VALUE(payload, &#039;$.customer.rank&#039; RETURNING SIGNED);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
JSON scalars participate in normal SQL coercion. A numeric result of &amp;lt;code&amp;gt;JSON_EXTRACT&amp;lt;/code&amp;gt;, for example, can be added, compared and sorted numerically. &amp;lt;code&amp;gt;NULL&amp;lt;/code&amp;gt; in SQL and the JSON literal &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt; remain distinct where the selected dialect distinguishes them.&lt;br /&gt;
&lt;br /&gt;
== Common MySQL JSON and SQL JSON queries ==&lt;br /&gt;
&lt;br /&gt;
=== Extract a value from JSON in SQL ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT JSON_EXTRACT(payload, &#039;$.customer.rank&#039;) AS rank&lt;br /&gt;
FROM events;&lt;br /&gt;
&lt;br /&gt;
SELECT payload-&amp;gt;&amp;gt;&#039;$.customer.name&#039; AS customer_name&lt;br /&gt;
FROM events;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Filter SQL rows by a JSON attribute ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT id&lt;br /&gt;
FROM events&lt;br /&gt;
WHERE JSON_VALUE(payload, &#039;$.customer.name&#039;) = &#039;Ada&#039;&lt;br /&gt;
	AND JSON_CONTAINS(payload, &#039;&amp;quot;sql&amp;quot;&#039;, &#039;$.tags&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Order SQL results by a JSON value ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT id, payload&lt;br /&gt;
FROM events&lt;br /&gt;
ORDER BY JSON_VALUE(payload, &#039;$.customer.rank&#039; RETURNING SIGNED), id;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The numeric &amp;lt;code&amp;gt;RETURNING&amp;lt;/code&amp;gt; type prevents lexical ordering such as &amp;lt;code&amp;gt;1, 10, 2&amp;lt;/code&amp;gt;. Eligible deterministic path expressions can be backed by a computed index.&lt;br /&gt;
&lt;br /&gt;
=== Aggregate SQL rows into a JSON array ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT category, JSON_ARRAYAGG(&lt;br /&gt;
	JSON_OBJECT(&#039;id&#039;, id, &#039;payload&#039;, payload)&lt;br /&gt;
) AS documents&lt;br /&gt;
FROM events&lt;br /&gt;
GROUP BY category;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Convert a JSON array into SQL rows ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT item.ord, item.name&lt;br /&gt;
FROM JSON_TABLE(&lt;br /&gt;
	&#039;[{&amp;quot;name&amp;quot;:&amp;quot;Ada&amp;quot;},{&amp;quot;name&amp;quot;:&amp;quot;Bob&amp;quot;}]&#039;,&lt;br /&gt;
	&#039;$[*]&#039; COLUMNS (&lt;br /&gt;
		ord FOR ORDINALITY,&lt;br /&gt;
		name TEXT PATH &#039;$.name&#039;&lt;br /&gt;
	)&lt;br /&gt;
) AS item;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== MySQL and MariaDB syntax ==&lt;br /&gt;
&lt;br /&gt;
MemCP implements the following MySQL/MariaDB-style JSON surface:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Area&lt;br /&gt;
! Functions and operators&lt;br /&gt;
|-&lt;br /&gt;
| Construction and aggregation&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_ARRAY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_OBJECT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_ARRAYAGG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_OBJECTAGG&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Inspection and extraction&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_EXTRACT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_VALUE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_KEYS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_LENGTH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_DEPTH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_VALID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Search and comparison&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_CONTAINS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_CONTAINS_PATH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_OVERLAPS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_SEARCH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;MEMBER OF&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Modification&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_SET&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_INSERT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_REPLACE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_REMOVE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_ARRAY_APPEND&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_ARRAY_INSERT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_MERGE_PATCH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_MERGE_PRESERVE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_MERGE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Conversion and formatting&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_QUOTE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_UNQUOTE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_PRETTY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_STORAGE_SIZE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_STORAGE_FREE&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Validation&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_SCHEMA_VALID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_SCHEMA_VALIDATION_REPORT&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Relational projection&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_TABLE&amp;lt;/code&amp;gt;, including path columns and &amp;lt;code&amp;gt;FOR ORDINALITY&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Paths start at &amp;lt;code&amp;gt;$&amp;lt;/code&amp;gt;. Object members, zero-based array indexes, wildcards, recursive descent and &amp;lt;code&amp;gt;last&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;last-N&amp;lt;/code&amp;gt; array indexes are supported.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT JSON_EXTRACT(&lt;br /&gt;
	&#039;{&amp;quot;orders&amp;quot;:[{&amp;quot;total&amp;quot;:10},{&amp;quot;total&amp;quot;:25}]}&#039;,&lt;br /&gt;
	&#039;$.orders[last].total&#039;&lt;br /&gt;
); -- 25&lt;br /&gt;
&lt;br /&gt;
SELECT *&lt;br /&gt;
FROM JSON_TABLE(&lt;br /&gt;
	&#039;[{&amp;quot;name&amp;quot;:&amp;quot;Ada&amp;quot;},{&amp;quot;name&amp;quot;:&amp;quot;Bob&amp;quot;}]&#039;,&lt;br /&gt;
	&#039;$[*]&#039; COLUMNS (&lt;br /&gt;
		ord FOR ORDINALITY,&lt;br /&gt;
		name TEXT PATH &#039;$.name&#039;&lt;br /&gt;
	)&lt;br /&gt;
) AS people;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The upstream references are MariaDB&#039;s [https://mariadb.com/docs/server/reference/sql-functions/special-functions/json-functions JSON functions index] and [https://mariadb.com/docs/server/reference/sql-functions/special-functions/json-functions/jsonpath-expressions JSONPath reference]. MariaDB adds functions over time; the table above is the supported MemCP surface, not a claim that every function in every MariaDB release is available.&lt;br /&gt;
&lt;br /&gt;
== PostgreSQL syntax ==&lt;br /&gt;
&lt;br /&gt;
The PostgreSQL-compatible parser accepts both &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;jsonb&amp;lt;/code&amp;gt; casts and column declarations. Internally both use the same native BSON representation.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Area&lt;br /&gt;
! Functions and operators&lt;br /&gt;
|-&lt;br /&gt;
| Extraction&lt;br /&gt;
| &amp;lt;code&amp;gt;-&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json_extract_path&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_extract_path&amp;lt;/code&amp;gt;, and their &amp;lt;code&amp;gt;_text&amp;lt;/code&amp;gt; variants&lt;br /&gt;
|-&lt;br /&gt;
| jsonb operators&lt;br /&gt;
| &amp;lt;code&amp;gt;@&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;&amp;lt;@&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;?|&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;?&amp;amp;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;||&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#-&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;@?&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;@@&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Construction and conversion&lt;br /&gt;
| &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;to_json&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;to_jsonb&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;array_to_json&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;row_to_json&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json_build_array&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_build_array&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json_build_object&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_build_object&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json_object&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_object&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json_scalar&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json_serialize&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Inspection and modification&lt;br /&gt;
| &amp;lt;code&amp;gt;json_array_length&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_array_length&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json_typeof&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_typeof&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_set&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_set_lax&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_insert&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json_strip_nulls&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_strip_nulls&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_pretty&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| Set-returning functions&lt;br /&gt;
| &amp;lt;code&amp;gt;json[b]_array_elements[_text]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json[b]_each[_text]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json[b]_object_keys&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json[b]_populate_record[set]&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_populate_record_valid&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;json[b]_to_record[set]&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| JSONPath&lt;br /&gt;
| &amp;lt;code&amp;gt;jsonb_path_exists&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_path_match&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_path_query&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_path_query_array&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_path_query_first&amp;lt;/code&amp;gt;, plus their &amp;lt;code&amp;gt;_tz&amp;lt;/code&amp;gt; variants&lt;br /&gt;
|-&lt;br /&gt;
| Aggregation&lt;br /&gt;
| &amp;lt;code&amp;gt;json_agg&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;jsonb_agg&amp;lt;/code&amp;gt;, strict variants, &amp;lt;code&amp;gt;json_object_agg&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;jsonb_object_agg&amp;lt;/code&amp;gt; and their &amp;lt;code&amp;gt;_strict&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;_unique&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;_unique_strict&amp;lt;/code&amp;gt; variants&lt;br /&gt;
|-&lt;br /&gt;
| SQL/JSON&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_ARRAY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_OBJECT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_ARRAYAGG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_OBJECTAGG&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_EXISTS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_QUERY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_VALUE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_TABLE&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT&lt;br /&gt;
	payload-&amp;gt;&#039;customer&#039;-&amp;gt;&amp;gt;&#039;name&#039; AS name,&lt;br /&gt;
	payload @&amp;gt; &#039;{&amp;quot;tags&amp;quot;:[&amp;quot;sql&amp;quot;]}&#039;::jsonb AS has_sql&lt;br /&gt;
FROM events&lt;br /&gt;
ORDER BY payload-&amp;gt;&#039;customer&#039;-&amp;gt;&#039;rank&#039;;&lt;br /&gt;
&lt;br /&gt;
SELECT jsonb_path_query_array(&lt;br /&gt;
	&#039;{&amp;quot;values&amp;quot;:[1,2,3,4]}&#039;::jsonb,&lt;br /&gt;
	&#039;$.values[*] ? (@ &amp;gt; 2)&#039;&lt;br /&gt;
); -- [3,4]&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
See PostgreSQL&#039;s official [https://www.postgresql.org/docs/current/functions-json.html JSON functions and operators] and [https://www.postgresql.org/docs/current/functions-aggregate.html aggregate functions] documentation for the source syntax and semantics. The tables above identify the forms currently accepted by MemCP.&lt;br /&gt;
&lt;br /&gt;
== Building nested application documents ==&lt;br /&gt;
&lt;br /&gt;
JSON constructors and aggregates compose with correlated subqueries. This allows a relational schema to emit complete API documents, including arrays nested several levels deep:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
SELECT JSON_OBJECT(&lt;br /&gt;
	&#039;id&#039;, delivery_note.id,&lt;br /&gt;
	&#039;number&#039;, delivery_note.note_number,&lt;br /&gt;
	&#039;date&#039;, delivery_note.delivery_date,&lt;br /&gt;
	&#039;items&#039;, (&lt;br /&gt;
		SELECT JSON_ARRAYAGG(JSON_OBJECT(&lt;br /&gt;
			&#039;id&#039;, delivery_item.id,&lt;br /&gt;
			&#039;sku&#039;, delivery_item.sku,&lt;br /&gt;
			&#039;quantity&#039;, delivery_item.quantity,&lt;br /&gt;
			&#039;serialNumbers&#039;, (&lt;br /&gt;
				SELECT JSON_ARRAYAGG(JSON_OBJECT(&lt;br /&gt;
					&#039;id&#039;, serial_number.id,&lt;br /&gt;
					&#039;value&#039;, serial_number.serial_number&lt;br /&gt;
				))&lt;br /&gt;
				FROM delivery_serial_numbers AS serial_number&lt;br /&gt;
				WHERE serial_number.delivery_item_id = delivery_item.id&lt;br /&gt;
			)&lt;br /&gt;
		))&lt;br /&gt;
		FROM delivery_items AS delivery_item&lt;br /&gt;
		WHERE delivery_item.delivery_note_id = delivery_note.id&lt;br /&gt;
	)&lt;br /&gt;
) AS document&lt;br /&gt;
FROM delivery_notes AS delivery_note&lt;br /&gt;
ORDER BY delivery_note.delivery_date DESC;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;JSON_ARRAYAGG&amp;lt;/code&amp;gt; collects values first and emits one exact-sized BSON array at aggregate finalization. Nested aggregation therefore avoids repeatedly copying a growing JSON string. The same finalization is applied independently to scalar subqueries, groups and set-operation branches.&lt;br /&gt;
&lt;br /&gt;
== Storage and indexing ==&lt;br /&gt;
&lt;br /&gt;
* A declared &amp;lt;code&amp;gt;JSON&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;JSONB&amp;lt;/code&amp;gt; column rejects invalid documents on &amp;lt;code&amp;gt;INSERT&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UPDATE&amp;lt;/code&amp;gt;.&lt;br /&gt;
* MemCP stores one native BSON value, not both a JSON string and a parsed tree. BSON is a normal tagged SCM value and needs no JSON-specific storage engine.&lt;br /&gt;
* Serialization is canonical rather than lexical: insignificant whitespace is not retained, object key order is deterministic, and duplicate object keys do not remain separate.&lt;br /&gt;
* JSON extraction expressions can be used in &amp;lt;code&amp;gt;WHERE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;GROUP BY&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ORDER BY&amp;lt;/code&amp;gt;. Eligible deterministic expressions can be materialized as computed columns and served by computed indexes, so document-style tables do not require reparsing every row for each query.&lt;br /&gt;
&lt;br /&gt;
For frequently filtered or sorted attributes, keep the JSON payload for flexibility and expose the hot path as a deterministic expression used consistently by queries. Fully relational columns remain preferable for keys, high-selectivity joins and attributes with strong schema constraints.&lt;br /&gt;
&lt;br /&gt;
== Compatibility notes ==&lt;br /&gt;
&lt;br /&gt;
MemCP aims at practical query compatibility, but it does not preserve PostgreSQL&#039;s textual &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt; representation separately from &amp;lt;code&amp;gt;jsonb&amp;lt;/code&amp;gt;, nor MariaDB&#039;s LONGTEXT representation. Native BSON is used for both dialects. Applications that depend on original whitespace, duplicate-key preservation or byte-for-byte round trips should store the original document in a separate text column.&lt;br /&gt;
&lt;br /&gt;
Unknown or newly introduced upstream JSON functions should be treated as unsupported until they appear in the supported tables above and in MemCP&#039;s compatibility tests.&lt;br /&gt;
&lt;br /&gt;
== Frequently asked questions about SQL JSON in MemCP ==&lt;br /&gt;
&lt;br /&gt;
=== Does MemCP support MySQL JSON functions? ===&lt;br /&gt;
&lt;br /&gt;
Yes. MemCP supports commonly used MySQL JSON functions and operators for construction, extraction, search, modification, aggregation, schema validation and &amp;lt;code&amp;gt;JSON_TABLE&amp;lt;/code&amp;gt;. The complete currently supported surface is listed under [[#MySQL and MariaDB syntax]].&lt;br /&gt;
&lt;br /&gt;
=== Can MemCP run JSON_EXTRACT and JSON_VALUE on a string? ===&lt;br /&gt;
&lt;br /&gt;
Yes. Both functions accept valid JSON text. A declared &amp;lt;code&amp;gt;JSON&amp;lt;/code&amp;gt; column is more efficient for repeated queries because MemCP validates and converts the document when it is written.&lt;br /&gt;
&lt;br /&gt;
=== Does MemCP support PostgreSQL JSONB? ===&lt;br /&gt;
&lt;br /&gt;
Yes. The PostgreSQL-compatible parser supports &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;jsonb&amp;lt;/code&amp;gt; casts, extraction and containment operators, JSONPath, constructors, aggregates and set-returning JSON functions. MemCP represents both SQL types with the same immutable BSON value internally.&lt;br /&gt;
&lt;br /&gt;
=== Can MemCP index a field inside a JSON document? ===&lt;br /&gt;
&lt;br /&gt;
JSON extraction can be used as a deterministic computed expression. When eligible, MemCP can materialize that expression and use a computed index for filters or ordering by the extracted JSON attribute.&lt;br /&gt;
&lt;br /&gt;
=== Should all application data be stored in one JSON column? ===&lt;br /&gt;
&lt;br /&gt;
It is possible to use a document-style table containing an ID, timestamps and a JSON payload. Relational columns are still preferable for primary keys, frequently joined keys and strongly constrained attributes. A hybrid schema normally gives the optimizer more options while retaining JSON flexibility.&lt;br /&gt;
&lt;br /&gt;
[[Category:SQL]]&lt;br /&gt;
[[Category:JSON]]&lt;br /&gt;
[[Category:MySQL]]&lt;br /&gt;
[[Category:PostgreSQL]]&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Current_Status_and_Open_Issues&amp;diff=272</id>
		<title>Current Status and Open Issues</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Current_Status_and_Open_Issues&amp;diff=272"/>
		<updated>2026-08-21T15:11:54Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;padding:1rem 1.2rem; margin:0 0 1.5rem; border-left:5px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Status: Beta · Verified against commit &amp;lt;code&amp;gt;e90d6ce7fd&amp;lt;/code&amp;gt; on 21 August 2026.&#039;&#039;&#039; MemCP is usable for tested workloads, but SQL compatibility and complex planner cases continue to evolve. Validate every application-critical query, durability requirement and client before a production migration.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This page describes the current implementation and the remaining publicly tracked work. It replaces the old static TODO list from November 2024. Active tasks and priorities belong in the [https://github.com/launix-de/memcp/issues GitHub issue tracker]; completed work belongs in the changelog and repository history.&lt;br /&gt;
&lt;br /&gt;
== Current status ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
! Area&lt;br /&gt;
! Status&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
| SQL frontend&lt;br /&gt;
| Broad support, Beta compatibility&lt;br /&gt;
| DDL, DML, joins, transactions, views, triggers, window functions, UNION and extensively tested subqueries are available. MemCP does not claim complete MySQL or PostgreSQL compatibility. See [[Supported SQL]].&lt;br /&gt;
|-&lt;br /&gt;
| Storage and durability&lt;br /&gt;
| Operational&lt;br /&gt;
| Per-table &amp;lt;code&amp;gt;safe&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;logged&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;sloppy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;memory&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;cache&amp;lt;/code&amp;gt; engines are implemented. See [[Persistency and Performance Guarantees]] before choosing or changing an engine.&lt;br /&gt;
|-&lt;br /&gt;
| Query planner&lt;br /&gt;
| New architecture implemented, actively optimized&lt;br /&gt;
| Logical decorrelation and join ordering are separated from cost-based physical lowering. RecSets, indexes, direct scans, group caches, ORC columns and pipeline variants are physical alternatives. See [[Query Planner and Physical Lowering]].&lt;br /&gt;
|-&lt;br /&gt;
| Transactions and constraints&lt;br /&gt;
| Implemented for tested semantics&lt;br /&gt;
| Cursor-stability transactions, an explicit ACID/OCC mode, rollback, unique and NOT NULL constraints, and enforced CREATE TABLE foreign keys are covered by tests. XA and complete MySQL isolation-level compatibility are not claimed.&lt;br /&gt;
|-&lt;br /&gt;
| Operations&lt;br /&gt;
| Implemented, still maturing&lt;br /&gt;
| Dashboard, metrics, processlist, query/connection cancellation, graceful shutdown, memory budgets and eviction are available.&lt;br /&gt;
|-&lt;br /&gt;
| Storage backends&lt;br /&gt;
| Implemented&lt;br /&gt;
| Local files, S3-compatible object storage and optional Ceph/RADOS are supported. Backend-specific outage, backup and latency behavior must be validated operationally.&lt;br /&gt;
|-&lt;br /&gt;
| RDF/SPARQL&lt;br /&gt;
| Supported subset&lt;br /&gt;
| Query, FILTER, OPTIONAL, update forms and Turtle loading are tested. This is not a claim of complete SPARQL standard coverage.&lt;br /&gt;
|-&lt;br /&gt;
| Scheme runtime&lt;br /&gt;
| Operational&lt;br /&gt;
| The functional runtime, concurrency primitives and native x86-64 JIT are integrated. Unsupported JIT shapes fall back to interpreted execution.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== What changed since the old roadmap ==&lt;br /&gt;
&lt;br /&gt;
The previous page was a development checklist. The table below preserves every old item and records what happened to it.&lt;br /&gt;
&lt;br /&gt;
=== Storage engine ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
! Original roadmap item&lt;br /&gt;
! Current result&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;ALTER TABLE … ENGINE&amp;lt;/code&amp;gt;&lt;br /&gt;
| &#039;&#039;&#039;Implemented.&#039;&#039;&#039; Tables can transition between the five MemCP engines. Some transitions change durability; persisted → &amp;lt;code&amp;gt;memory&amp;lt;/code&amp;gt; permanently removes on-disk data.&lt;br /&gt;
|-&lt;br /&gt;
| LRU garbage collection for temporary columns&lt;br /&gt;
| &#039;&#039;&#039;Implemented and expanded.&#039;&#039;&#039; Global memory budgets cover persisted columns, indexes, temporary/computed columns, keytables, cache tables and dictionaries. Reloadable data can be evicted; memory-engine rows cannot.&lt;br /&gt;
|-&lt;br /&gt;
| Triggers and change hooks on computed columns&lt;br /&gt;
| &#039;&#039;&#039;Implemented.&#039;&#039;&#039; Persistent SQL triggers and hidden dependency/invalidation triggers maintain computed columns, group caches, prejoins and order-dependent caches.&lt;br /&gt;
|-&lt;br /&gt;
| Respect foreign keys&lt;br /&gt;
| &#039;&#039;&#039;Implemented for foreign keys declared with CREATE TABLE.&#039;&#039;&#039; RESTRICT, CASCADE and SET NULL paths are tested for inserts, deletes and key updates. Some ALTER TABLE foreign-key forms remain compatibility-only syntax.&lt;br /&gt;
|-&lt;br /&gt;
| Serialize into memory-mapped database-sized key/value files&lt;br /&gt;
| &#039;&#039;&#039;Not adopted as the persistence architecture.&#039;&#039;&#039; MemCP retains versioned per-column storage and WAL files and now also supports object backends. Selected storage/JIT implementations use mmap internally, but there is no single 100-GiB database blob contract.&lt;br /&gt;
|-&lt;br /&gt;
| Sort index delta storage and merge it with the main index&lt;br /&gt;
| &#039;&#039;&#039;Implemented.&#039;&#039;&#039; Ordered iteration merges the compressed main permutation with an ordered index-local delta structure.&lt;br /&gt;
|-&lt;br /&gt;
| Multi-table &amp;lt;code&amp;gt;scan_star&amp;lt;/code&amp;gt;/merge-join operator&lt;br /&gt;
| &#039;&#039;&#039;Superseded by the current planner.&#039;&#039;&#039; Logical join trees are reordered and lowered into costed nested, parallel, indexed, ordered, RecSet or cached physical paths instead of one mandatory combined operator.&lt;br /&gt;
|-&lt;br /&gt;
| Process IDs, request context and kill switch&lt;br /&gt;
| &#039;&#039;&#039;Implemented.&#039;&#039;&#039; &amp;lt;code&amp;gt;SHOW [FULL] PROCESSLIST&amp;lt;/code&amp;gt;, dashboard process controls, &amp;lt;code&amp;gt;KILL QUERY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;KILL CONNECTION&amp;lt;/code&amp;gt; and cancellation-aware table waits are available.&lt;br /&gt;
|-&lt;br /&gt;
| Transaction insertion/deletion overlays and conflict handling&lt;br /&gt;
| &#039;&#039;&#039;Implemented and expanded.&#039;&#039;&#039; The storage engine provides cursor-stability undo handling plus snapshot/OCC transaction infrastructure, shard visibility, commit conflict checks, rollback and WAL synchronization at commit.&lt;br /&gt;
|-&lt;br /&gt;
| Indexes for LIKE queries&lt;br /&gt;
| &#039;&#039;&#039;Implemented.&#039;&#039;&#039; LIKE-prefix and adaptive match-set boundaries participate in scan and physical cost decisions. Residual predicates remain when a boundary is not an exact proof.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== RDF frontend ===&lt;br /&gt;
&lt;br /&gt;
The three former RDF items are implemented and covered by integration tests:&lt;br /&gt;
&lt;br /&gt;
* SPARQL update with &amp;lt;code&amp;gt;DELETE { … } INSERT { … } WHERE { … }&amp;lt;/code&amp;gt;;&lt;br /&gt;
* update templates driven by SELECT/WHERE bindings;&lt;br /&gt;
* &amp;lt;code&amp;gt;OPTIONAL { … }&amp;lt;/code&amp;gt; with left-join behavior, including unmatched and multiple optional blocks.&lt;br /&gt;
&lt;br /&gt;
RDF support remains a tested subset. Unsupported SPARQL syntax should not be inferred from the implementation of these constructs.&lt;br /&gt;
&lt;br /&gt;
=== SQL frontend ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
! Original roadmap item&lt;br /&gt;
! Current result&lt;br /&gt;
|-&lt;br /&gt;
| AUTO_INCREMENT&lt;br /&gt;
| &#039;&#039;&#039;Implemented and persisted&#039;&#039;&#039;, including restart and ALTER TABLE behavior.&lt;br /&gt;
|-&lt;br /&gt;
| Convert subqueries into joins&lt;br /&gt;
| &#039;&#039;&#039;Implemented far beyond the original item.&#039;&#039;&#039; The logical planner decorrelates scalar, IN/NOT IN and EXISTS/NOT EXISTS shapes using Neumann-style domains before join reordering and physical lowering.&lt;br /&gt;
|-&lt;br /&gt;
| Shard group tables like their group keys&lt;br /&gt;
| &#039;&#039;&#039;Implemented as a physical option.&#039;&#039;&#039; Group keytables can be partitioned from group-key information when the cost model selects reusable materialization.&lt;br /&gt;
|-&lt;br /&gt;
| Prejoin complex plans&lt;br /&gt;
| &#039;&#039;&#039;Implemented as one of several alternatives.&#039;&#039;&#039; Prejoins, FK/PK group reuse, group caches, direct scans and RecSets compete according to semantics and cost.&lt;br /&gt;
|-&lt;br /&gt;
| Restrict users to databases&lt;br /&gt;
| &#039;&#039;&#039;Implemented.&#039;&#039;&#039; Users, grants, revokes and database access policies are represented in system metadata and enforced by the SQL/API frontends.&lt;br /&gt;
|-&lt;br /&gt;
| Test DBeaver, phpMyAdmin and metadata compatibility&lt;br /&gt;
| &#039;&#039;&#039;Ongoing compatibility work.&#039;&#039;&#039; MySQL protocol, prepared statements, SHOW metadata and selected INFORMATION_SCHEMA relations are implemented, but individual client releases still require dated compatibility tests.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Scheme language and infrastructure ===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Native JIT: implemented.&#039;&#039;&#039; Supported hot Scheme procedures can be compiled to x86-64 machine code, including an expanding set of calls, control flow and planner-generated lambdas. Unsupported procedures continue in the interpreter.&lt;br /&gt;
* &#039;&#039;&#039;HTTP/IPFS stream filenames: not generally implemented.&#039;&#039;&#039; Local files and supported virtual archive paths are available; arbitrary &amp;lt;code&amp;gt;http://&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;ipfs://&amp;lt;/code&amp;gt; loading should not be documented as supported.&lt;br /&gt;
* &#039;&#039;&#039;General native plugin system: not implemented as a stable public API.&#039;&#039;&#039; MemCP has extension hooks such as storage boundary matchers and embedded Scheme modules, but no promised ABI for arbitrary C++/GPU plugins.&lt;br /&gt;
&lt;br /&gt;
== Current roadmap ==&lt;br /&gt;
&lt;br /&gt;
There is currently no published release milestone with a fixed feature schedule. As of the verification date, the public issue tracker contains one open feature issue:&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/launix-de/memcp/issues/9 #9 – Vector extension: helper functions]&lt;br /&gt;
&lt;br /&gt;
=== Next SQL roadmap: JSON compatibility ===&lt;br /&gt;
&lt;br /&gt;
JSON support is planned as a compatibility and integration feature, not as a replacement for relational modelling. Frequently queried fields should normally remain typed columns with constraints, statistics and indexes. JSON is useful for sparse external attributes, application payloads and migration compatibility; the SQL interface must still make extraction into relational rows and typed values straightforward.&lt;br /&gt;
&lt;br /&gt;
MemCP already has JSONL import, JSON serialization for HTTP and Scheme, and type mapping for MySQL &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt; and PostgreSQL &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;jsonb&amp;lt;/code&amp;gt; imports. These facilities do not yet constitute MySQL, PostgreSQL or SQL/JSON query compatibility.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
! Phase&lt;br /&gt;
! Planned scope&lt;br /&gt;
! Required semantic decisions&lt;br /&gt;
|-&lt;br /&gt;
| 1. JSON value contract&lt;br /&gt;
| A documented SQL JSON type/storage contract; validation and canonical serialization; &amp;lt;code&amp;gt;JSON_VALID&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_TYPE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_QUOTE&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;JSON_UNQUOTE&amp;lt;/code&amp;gt;; casts between text and JSON.&lt;br /&gt;
| Distinguish SQL NULL, JSON &amp;lt;code&amp;gt;null&amp;lt;/code&amp;gt; and a missing path; preserve numeric precision; define duplicate-object-key behavior, invalid-input errors and equality/comparison rules before adding optimizer shortcuts.&lt;br /&gt;
|-&lt;br /&gt;
| 2. Paths and read access&lt;br /&gt;
| MySQL-compatible &amp;lt;code&amp;gt;JSON_EXTRACT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_VALUE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_QUERY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_EXISTS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;-&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;; &amp;lt;code&amp;gt;JSON_LENGTH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_DEPTH&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_KEYS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_CONTAINS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_CONTAINS_PATH&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;JSON_SEARCH&amp;lt;/code&amp;gt; where compatible semantics are defined.&lt;br /&gt;
| Define one parsed path representation shared by functions and operators. Constant paths should be parsed once, not once per row. Dynamic paths must have explicit cost and error behavior.&lt;br /&gt;
|-&lt;br /&gt;
| 3. Construction and aggregation&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_OBJECT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_ARRAY&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_OBJECTAGG&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;JSON_ARRAYAGG&amp;lt;/code&amp;gt; with deterministic documented handling of NULLs, duplicate keys and aggregate ordering.&lt;br /&gt;
| Constructors must not silently conflate Scheme association lists, SQL rows and JSON objects. Aggregate results need stable semantics across shards and parallel execution.&lt;br /&gt;
|-&lt;br /&gt;
| 4. Mutation&lt;br /&gt;
| &amp;lt;code&amp;gt;JSON_SET&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_INSERT&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_REPLACE&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;JSON_REMOVE&amp;lt;/code&amp;gt;, array append/insert functions and merge-patch behavior.&lt;br /&gt;
| Functions remain pure expressions; an SQL UPDATE writes the resulting JSON value. Partial-update storage optimization may follow later but must not change transactional, trigger or durability semantics.&lt;br /&gt;
|-&lt;br /&gt;
| 5. Relational projection&lt;br /&gt;
| SQL/JSON &amp;lt;code&amp;gt;JSON_TABLE&amp;lt;/code&amp;gt; or an equivalent table-producing operator, with typed columns, nested paths, defaults and explicit error/empty behavior.&lt;br /&gt;
| JSON expansion belongs in the logical relational plan and must participate correctly in joins, correlation, NULL extension, cardinality estimation and cancellation. It must not be hidden as an uncosted per-row fallback.&lt;br /&gt;
|-&lt;br /&gt;
| 6. Indexing and physical optimization&lt;br /&gt;
| Reusable computed columns and adaptive indexes over stable JSON path expressions; statistics for extracted scalar values; batch extraction for scans.&lt;br /&gt;
| Optimize declared path expressions rather than pretending an opaque document is relationally indexed. Invalidating or updating a JSON document must invalidate every dependent extracted value safely.&lt;br /&gt;
|-&lt;br /&gt;
| 7. Dialect compatibility&lt;br /&gt;
| Map PostgreSQL &amp;lt;code&amp;gt;json&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;jsonb&amp;lt;/code&amp;gt; extraction and containment operators such as &amp;lt;code&amp;gt;-&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;-&amp;gt;&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#&amp;gt;&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;#&amp;gt;&amp;gt;&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;@&amp;gt;&amp;lt;/code&amp;gt; onto the same semantic core where behavior is genuinely compatible.&lt;br /&gt;
| MySQL, PostgreSQL and SQL/JSON differ in path grammar, scalar return types, ordering, containment and errors. Dialect spellings may share internals, but must not be advertised as aliases when their observable semantics differ.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Definition of done for every JSON feature:&lt;br /&gt;
&lt;br /&gt;
* successful and must-fail SQL tests for SQL NULL, JSON null, missing paths, malformed JSON and malformed paths;&lt;br /&gt;
* MySQL and PostgreSQL dialect tests where the feature is advertised for both;&lt;br /&gt;
* persistence/restart, trigger, transaction and prepared-statement coverage;&lt;br /&gt;
* batch and allocation benchmarks before enabling path extraction in scan hot loops;&lt;br /&gt;
* EXPLAIN visibility for table expansion, computed extraction and index use;&lt;br /&gt;
* explicit documentation of deviations from MySQL, PostgreSQL or the SQL/JSON standard.&lt;br /&gt;
&lt;br /&gt;
No phase above has a promised release date. Before implementation starts, the agreed compatibility slice should be represented by one or more GitHub issues and tests, rather than treating every vendor-specific JSON function as automatically in scope.&lt;br /&gt;
&lt;br /&gt;
Recent development has concentrated on correctness and cost calibration of the planner, RecSet representations and bulk scans, JIT coverage, shard rebuild concurrency and query cancellation. Git history shows completed changes; it does not constitute a delivery promise for future work.&lt;br /&gt;
&lt;br /&gt;
Areas that continue to need testing and incremental improvement include:&lt;br /&gt;
&lt;br /&gt;
* MySQL/PostgreSQL syntax and metadata compatibility required by real applications;&lt;br /&gt;
* rare combinations of correlated subqueries, outer joins, UNION, grouping, windows and SQL three-valued logic;&lt;br /&gt;
* transaction contention, long-running rebuilds and crash recovery across engine/backends;&lt;br /&gt;
* ORM, administration-tool and connector compatibility by concrete version;&lt;br /&gt;
* non-x86-64 platform behavior where native JIT acceleration is unavailable;&lt;br /&gt;
* reproducible performance measurements across representative workloads.&lt;br /&gt;
&lt;br /&gt;
These are quality areas, not commitments to a particular release date. Concrete work should be represented by a GitHub issue before this page calls it scheduled.&lt;br /&gt;
&lt;br /&gt;
== Reporting an issue ==&lt;br /&gt;
&lt;br /&gt;
Please open a [https://github.com/launix-de/memcp/issues/new GitHub issue] with:&lt;br /&gt;
&lt;br /&gt;
* MemCP version or commit;&lt;br /&gt;
* frontend used: MySQL protocol, &amp;lt;code&amp;gt;/sql&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;/psql&amp;lt;/code&amp;gt;, RDF or embedded Scheme;&lt;br /&gt;
* minimal schema, setup data and query;&lt;br /&gt;
* expected and actual result;&lt;br /&gt;
* table ENGINE and storage backend;&lt;br /&gt;
* whether the problem reproduces after a clean restart;&lt;br /&gt;
* for performance reports: row counts, EXPLAIN output, hardware, concurrency, cache state, successful response validation and raw samples.&lt;br /&gt;
&lt;br /&gt;
See [[Contributing]] for the development and test workflow.&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Main_Page&amp;diff=271</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Main_Page&amp;diff=271"/>
		<updated>2026-08-21T14:23:48Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= MemCP – A Modern In-Memory Columnar Database =&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:2.5rem 2rem; margin:0 0 1.5rem; border-radius:14px; background:linear-gradient(135deg,#3d6208 0%,#64910c 52%,#76b512 100%); color:#fff; text-align:center;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:2.6rem; line-height:1.1; font-weight:700; margin-bottom:.7rem;&amp;quot;&amp;gt;MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.45rem; line-height:1.35; font-weight:600; margin:0 auto .9rem; max-width:56rem;&amp;quot;&amp;gt;A fast, compressed, MySQL-compatible columnar database for modern OLTP and OLAP workloads&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.05rem; line-height:1.6; margin:0 auto 1.4rem; max-width:54rem;&amp;quot;&amp;gt;MemCP combines persistent in-memory operation, adaptive column compression, parallel query execution and direct application APIs in a lightweight database written in Go.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;margin-bottom:1.5rem;&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;Beta&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;Open Source&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; padding:.2rem .65rem; margin:.15rem; border:1px solid #ffffff88; border-radius:1rem;&amp;quot;&amp;gt;MySQL Protocol + HTTP APIs&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;plainlinks&amp;quot;&amp;gt;&amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[[Install MemCP with Docker|&amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border-radius:6px; background:#fff; color:#496f0c; font-weight:700;&amp;quot;&amp;gt;Get started with Docker&amp;lt;/span&amp;gt;]]&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[[Supported SQL|&amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border:1px solid #fff; border-radius:6px; color:#fff; font-weight:700;&amp;quot;&amp;gt;Explore SQL support&amp;lt;/span&amp;gt;]]&amp;lt;/span&amp;gt; &amp;lt;span style=&amp;quot;display:inline-block; margin:.25rem;&amp;quot;&amp;gt;[https://github.com/launix-de/memcp &amp;lt;span style=&amp;quot;display:inline-block; padding:.65rem 1rem; border:1px solid #fff; border-radius:6px; color:#fff; font-weight:700;&amp;quot;&amp;gt;View on GitHub&amp;lt;/span&amp;gt;]&amp;lt;/span&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:Memcp-Load.png|center|frameless|1000px|alt=MemCP database dashboard and workload overview]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.85rem 1rem; margin:1rem 0 2rem; border-left:5px solid #d99b00; background:#fff7d6; color:#332600;&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Development status: Beta.&#039;&#039;&#039; MemCP is under active development. Check [[Supported SQL]], [[Current Status and Open Issues]] and the durability requirements of your workload before migrating production data.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Choose your path ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(220px,1fr)); gap:1rem; margin:1rem 0 2rem;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Evaluate MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
Understand the workload model, current status, hardware needs and differences from MySQL.&lt;br /&gt;
&lt;br /&gt;
[[What is OLTP and OLAP|OLTP and OLAP]] · [[Comparison: MemCP vs. MySQL|Compare with MySQL]] · [[Hardware Requirements|Hardware requirements]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Build an application&amp;lt;/div&amp;gt;&lt;br /&gt;
Use the MySQL protocol, SQL over HTTP, RDF or application-specific endpoints inside MemCP.&lt;br /&gt;
&lt;br /&gt;
[[Advanced SQL Tutorial|SQL tutorial]] · [[SQL over REST|SQL over HTTP]] · [[Database Tools compatibility with MemCP|Client tooling]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Operate MemCP&amp;lt;/div&amp;gt;&lt;br /&gt;
Plan deployment, migration, persistence, storage backends, settings and performance measurement.&lt;br /&gt;
&lt;br /&gt;
[[Deployment]] · [[Persistency and Performance Guarantees|Durability]] · [[Migration from MySQL and PostgreSQL|Migration]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:1rem 1.1rem; border:1px solid #b7c99a; border-radius:9px;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;font-size:1.15rem; font-weight:700; margin-bottom:.4rem;&amp;quot;&amp;gt;Understand and contribute&amp;lt;/div&amp;gt;&lt;br /&gt;
Explore the storage engine, optimizer, embedded Scheme runtime and project internals.&lt;br /&gt;
&lt;br /&gt;
[[Query Planner and Physical Lowering|Query planner]] · [[Columnar Storage]] · [[Contributing]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
&lt;br /&gt;
=== Run with Docker ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
docker run --name memcp \&lt;br /&gt;
  -e ROOT_PASSWORD=&#039;choose-a-password&#039; \&lt;br /&gt;
  -p 4321:4321 -p 3307:3307 \&lt;br /&gt;
  carli2/memcp:latest&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then open &amp;lt;code&amp;gt;http://localhost:4321&amp;lt;/code&amp;gt; and connect a MySQL application to &amp;lt;code&amp;gt;127.0.0.1&amp;lt;/code&amp;gt; on port &#039;&#039;&#039;3307&#039;&#039;&#039;. Add a volume mounted at &amp;lt;code&amp;gt;/data&amp;lt;/code&amp;gt; when the container must retain persistent data. See [[Install MemCP with Docker|the complete Docker guide]] before deploying it as a service.&lt;br /&gt;
&lt;br /&gt;
=== Build from source ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
git clone https://github.com/launix-de/memcp&lt;br /&gt;
cd memcp&lt;br /&gt;
go mod download&lt;br /&gt;
make&lt;br /&gt;
./memcp --api-port=4321 --mysql-port=3307 lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connect with MySQL tooling:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
mysql -h 127.0.0.1 -u root -p -P 3307&lt;br /&gt;
# Enter the password selected for this data directory.&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The development default for a fresh data directory is &amp;lt;code&amp;gt;admin&amp;lt;/code&amp;gt;. Change it before exposing MemCP to another machine. MemCP can also be supervised with PM2:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;&lt;br /&gt;
pm2 start ./memcp --name memcp -- \&lt;br /&gt;
  --no-repl -data ./data --api-port=4321 --mysql-port=3307 lib/main.scm&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Background deployments must use &amp;lt;code&amp;gt;--no-repl&amp;lt;/code&amp;gt; so that closing standard input does not terminate the interactive console and stop the server. See [[Compile MemCP from Source|Build from Source]], [[Deployment]] and [[MemCP Console]].&lt;br /&gt;
&lt;br /&gt;
== Key features ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display:grid; grid-template-columns:repeat(auto-fit,minmax(260px,1fr)); gap:.8rem; margin:1rem 0;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;High performance&#039;&#039;&#039;&amp;lt;br /&amp;gt;NUMA-aware, parallelized query execution is optimized for multicore CPUs, large caches and NVMe SSDs, serving both OLTP and OLAP workloads.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Columnar storage&#039;&#039;&#039;&amp;lt;br /&amp;gt;Data is stored by column for improved compression, a smaller memory footprint and fast analytical access.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Persistent in-memory operation&#039;&#039;&#039;&amp;lt;br /&amp;gt;MemCP is designed to keep active data in memory while offering configurable per-table durability and persistence backends.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Built-in APIs&#039;&#039;&#039;&amp;lt;br /&amp;gt;SQL over HTTP and in-database services can remove an extra middleware hop for suitable applications.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Adaptive compression&#039;&#039;&#039;&amp;lt;br /&amp;gt;Bit-packing, dictionary encoding and sequence compression can reduce suitable datasets by up to 80% compared with their MySQL/MariaDB representation.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Simple deployment&#039;&#039;&#039;&amp;lt;br /&amp;gt;Start with Docker, PM2 or the native binary. The compact application has historically had an installation footprint of approximately 10 MB.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #76b512; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Extensible frontends&#039;&#039;&#039;&amp;lt;br /&amp;gt;The Go storage engine and embedded Scheme environment support SQL, RDF, REST and custom application interfaces.&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div style=&amp;quot;padding:.9rem 1rem; border-top:4px solid #9ad32d; background:#f5f8f0; color:#17202a;&amp;quot;&amp;gt;&#039;&#039;&#039;Cost-based query execution&#039;&#039;&#039;&amp;lt;br /&amp;gt;Logical decorrelation and join optimization are separated from cost-based physical selection of scans, indexes, RecSets, reusable caches and execution pipelines.&amp;lt;br /&amp;gt;[[Query Planner and Physical Lowering|How MemCP plans and lowers queries →]]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Why MemCP? ==&lt;br /&gt;
&lt;br /&gt;
Traditional relational databases were designed around spinning disks and comparatively small numbers of CPU cores. MemCP rethinks storage and query execution for modern multicore systems, large caches, fast storage and mixed workloads.&lt;br /&gt;
&lt;br /&gt;
Typical use cases include:&lt;br /&gt;
&lt;br /&gt;
* real-time dashboards and analytics;&lt;br /&gt;
* data-heavy SaaS platforms;&lt;br /&gt;
* embedded systems with limited resources;&lt;br /&gt;
* high-throughput OLTP/OLAP hybrids.&lt;br /&gt;
&lt;br /&gt;
Whether MemCP is a good fit depends on the required SQL compatibility, durability, query mix, data size and operational environment. Review [[Supported SQL]], [[Persistency and Performance Guarantees]] and [[Performance Measurement]] rather than treating benchmark figures as universal guarantees.&lt;br /&gt;
&lt;br /&gt;
== MemCP vs. MySQL ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; style=&amp;quot;width:100%;&amp;quot;&lt;br /&gt;
! Feature&lt;br /&gt;
! MySQL&lt;br /&gt;
! MemCP&lt;br /&gt;
|-&lt;br /&gt;
| Storage model&lt;br /&gt;
| Primarily row-based&lt;br /&gt;
| Column-based and compressed&lt;br /&gt;
|-&lt;br /&gt;
| Performance focus&lt;br /&gt;
| General-purpose relational workloads&lt;br /&gt;
| NUMA-aware, in-memory execution for mixed operational and analytical workloads&lt;br /&gt;
|-&lt;br /&gt;
| In-memory capability&lt;br /&gt;
| Available through selected engines and caching&lt;br /&gt;
| Central design goal and default operating model&lt;br /&gt;
|-&lt;br /&gt;
| REST API integration&lt;br /&gt;
| Normally external&lt;br /&gt;
| Built in&lt;br /&gt;
|-&lt;br /&gt;
| Installation footprint&lt;br /&gt;
| Common server installations are approximately 150 MB or larger&lt;br /&gt;
| The native application has historically been approximately 10 MB&lt;br /&gt;
|-&lt;br /&gt;
| Open source&lt;br /&gt;
| ✅&lt;br /&gt;
| ✅&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
MemCP provides MySQL protocol compatibility but does not claim to implement every MySQL feature. See [[Comparison: MemCP vs. MySQL]] for a detailed comparison and [[Database Tools compatibility with MemCP]] for client compatibility.&lt;br /&gt;
&lt;br /&gt;
== Architecture overview ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tables, schemas and columns&#039;&#039;&#039;: Familiar SQL structures use a compressed columnar physical layout. See [[Databases, Tables and Columns]] and [[Columnar Storage]].&lt;br /&gt;
* &#039;&#039;&#039;Transaction model&#039;&#039;&#039;: Delta and main storage support mixed OLTP and OLAP semantics. See [[Transactions and Isolation]] and [[Shards, RecordIDs, Main Storage, Delta Storage]].&lt;br /&gt;
* &#039;&#039;&#039;Query planning&#039;&#039;&#039;: Logical optimization is separated from physical execution decisions. See [[Query Planner and Physical Lowering]].&lt;br /&gt;
* &#039;&#039;&#039;Persistence&#039;&#039;&#039;: Per-table durability can use filesystem, S3 or Ceph/RADOS storage. See [[Persistency and Performance Guarantees]].&lt;br /&gt;
* &#039;&#039;&#039;Frontends&#039;&#039;&#039;: MemCP provides multiple query and application interfaces:&lt;br /&gt;
** SQL through the MySQL wire protocol and SQL over HTTP;&lt;br /&gt;
** an RDF/graph query frontend;&lt;br /&gt;
** custom APIs through in-database web applications.&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
The following navigation remains on the start page so users and search engines can reach every major documentation area directly.&lt;br /&gt;
&lt;br /&gt;
=== Introduction and evaluation ===&lt;br /&gt;
&lt;br /&gt;
* [[What is OLTP and OLAP]]&lt;br /&gt;
* [[History of the MemCP project]]&lt;br /&gt;
* [[Hardware Requirements]]&lt;br /&gt;
* [[Persistency and Performance Guarantees]]&lt;br /&gt;
* [[Current Status and Open Issues]]&lt;br /&gt;
* [[Comparison: MemCP vs. MySQL]]&lt;br /&gt;
&lt;br /&gt;
=== Getting started ===&lt;br /&gt;
&lt;br /&gt;
* [[Install MemCP with Docker|Install with Docker]]&lt;br /&gt;
* [[With Singularity|Install with Singularity/Apptainer]]&lt;br /&gt;
* [[Compile MemCP from Source|Build from Source]]&lt;br /&gt;
* [[Contributing]]&lt;br /&gt;
* [[Introduction to Scheme]]&lt;br /&gt;
* [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
=== Administration ===&lt;br /&gt;
&lt;br /&gt;
* [[Deployment]]&lt;br /&gt;
* [[Migration from MySQL and PostgreSQL]]&lt;br /&gt;
* [[Settings]]&lt;br /&gt;
* [[Process Hibernation]]&lt;br /&gt;
* [[Performance Measurement]]&lt;br /&gt;
* [[MemCP Console]]&lt;br /&gt;
&lt;br /&gt;
=== Frontends ===&lt;br /&gt;
&lt;br /&gt;
==== SQL frontend ====&lt;br /&gt;
&lt;br /&gt;
* [[Supported SQL]]&lt;br /&gt;
* [[Advanced SQL Tutorial]]&lt;br /&gt;
* [[SQL over REST]]&lt;br /&gt;
* [[Database Tools compatibility with MemCP|Supported Tooling]]&lt;br /&gt;
* [[How SQL Operators are implemented on MemCP]]&lt;br /&gt;
* [[Add custom SQL operators to MemCP]]&lt;br /&gt;
&lt;br /&gt;
==== RDF frontend ====&lt;br /&gt;
&lt;br /&gt;
* [[Introduction to RDF]]&lt;br /&gt;
* [[Advanced Graph Querying]]&lt;br /&gt;
* [[RDF templating and model driven development]]&lt;br /&gt;
&lt;br /&gt;
==== Custom frontends ====&lt;br /&gt;
&lt;br /&gt;
* [[In-Database WebApps|In-Database WebApps and REST Services]]&lt;br /&gt;
* [[MemCP for Microservices]]&lt;br /&gt;
* [[Websockets in MemCP]]&lt;br /&gt;
&lt;br /&gt;
=== Persistence backends and storage ===&lt;br /&gt;
&lt;br /&gt;
* [[File System]]&lt;br /&gt;
* [[S3 Buckets]]&lt;br /&gt;
* [[Ceph/Rados]]&lt;br /&gt;
* [[Cluster Monitor]]&lt;br /&gt;
&lt;br /&gt;
=== Internals ===&lt;br /&gt;
&lt;br /&gt;
==== How MemCP works ====&lt;br /&gt;
&lt;br /&gt;
* [[Databases, Tables and Columns]]&lt;br /&gt;
* [[Shards, RecordIDs, Main Storage, Delta Storage]]&lt;br /&gt;
* [[Columnar Storage]]&lt;br /&gt;
* [[Transactions and Isolation]]&lt;br /&gt;
* [[Query Planner and Physical Lowering]]&lt;br /&gt;
* [[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
==== Scheme documentation ====&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
&lt;br /&gt;
==== Optimizations ====&lt;br /&gt;
&lt;br /&gt;
* [[Query Planner and Physical Lowering]]&lt;br /&gt;
* [[In-Memory Compression, Columnar Compression Techniques]]&lt;br /&gt;
* [[Temporary Columns]]&lt;br /&gt;
* [[Data Auto Sharding and Auto Indexing]]&lt;br /&gt;
* [[Parallel Computing]]&lt;br /&gt;
&lt;br /&gt;
== Further reading ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.com/launix-de/memcp MemCP on GitHub]&lt;br /&gt;
* [https://www.vldb.org/pvldb/vol13/p2649-boncz.pdf VLDB Research Paper]&lt;br /&gt;
* [https://cs.emis.de/LNI/Proceedings/Proceedings241/383.pdf LNI Proceedings Paper]&lt;br /&gt;
* [https://www.dcs.bbk.ac.uk/~dell/teaching/cc/paper/sigmod10/p135-malewicz.pdf Large Graph Algorithms]&lt;br /&gt;
&lt;br /&gt;
Additional blog posts on design decisions, compression techniques and performance optimization are available on the [https://launix.de/launix/ Launix blog].&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
&lt;br /&gt;
MemCP is an open-source project maintained by developers for developers. Contributions are welcome in the form of bug reports, feature requests and pull requests.&lt;br /&gt;
&lt;br /&gt;
See [[Contributing]] and the [https://github.com/launix-de/memcp GitHub repository].&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Main_Page&amp;diff=270</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Main_Page&amp;diff=270"/>
		<updated>2026-08-21T11:27:06Z</updated>

		<summary type="html">&lt;p&gt;Carli: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= MemCP – A Modern In-Memory Columnar Database =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP is a high-performance, in-memory, column-oriented database designed for modern workloads.&#039;&#039;&#039;  &lt;br /&gt;
It provides a lightweight, developer-friendly alternative to traditional relational databases such as MySQL, with a focus on speed, compression, and direct API integration.&lt;br /&gt;
[[File:Memcp-Load.png|center|frameless|1600x1600px]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Quickstart ==&lt;br /&gt;
   docker run --name memcp \&lt;br /&gt;
     -e ROOT_PASSWORD=&#039;choose-a-password&#039; \&lt;br /&gt;
     -p 4321:4321 -p 3307:3307 \&lt;br /&gt;
     carli2/memcp:latest&lt;br /&gt;
Then open http://localhost:4321 and connect your MySQL application via 127.0.0.1 port &#039;&#039;&#039;3307&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== Key Features ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;High Performance&#039;&#039;&#039;: NUMA-aware, parallelized query execution optimized for multicore CPUs, large caches, and NVMe SSDs. Handles both OLTP and OLAP workloads efficiently.  &lt;br /&gt;
* &#039;&#039;&#039;Columnar Storage&#039;&#039;&#039;: Data is stored by column for improved compression, reduced memory footprint, and faster analytical queries.  &lt;br /&gt;
* &#039;&#039;&#039;In-Memory Operation&#039;&#039;&#039;: Designed to keep data in memory, with configurable persistence backends for durability.  &lt;br /&gt;
* &#039;&#039;&#039;Built-in APIs&#039;&#039;&#039;: Exposes RESTful endpoints directly from the database, reducing middleware overhead.  &lt;br /&gt;
* &#039;&#039;&#039;Compression&#039;&#039;&#039;: Multiple strategies (bit-packing, dictionary encoding, sequence compression) reduce storage by up to 80% compared to MySQL/MariaDB.  &lt;br /&gt;
* &#039;&#039;&#039;Simple Deployment&#039;&#039;&#039;: Start with a single &amp;lt;code&amp;gt;docker run&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;pm2 start&amp;lt;/code&amp;gt; command. Lightweight footprint (~10MB).  &lt;br /&gt;
* &#039;&#039;&#039;Extensible&#039;&#039;&#039;: Written in Go, with pluggable storage backends and custom frontend support (SQL, RDF, REST).  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Why MemCP? ==&lt;br /&gt;
&lt;br /&gt;
Traditional relational databases were designed decades ago, optimized for spinning disks and single-core CPUs.  &lt;br /&gt;
MemCP rethinks the core design for today’s hardware and workloads:&lt;br /&gt;
&lt;br /&gt;
* Real-time dashboards and analytics  &lt;br /&gt;
* Data-heavy SaaS platforms  &lt;br /&gt;
* Embedded systems with limited resources  &lt;br /&gt;
* High-throughput OLTP/OLAP hybrids  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
Clone and build MemCP from source:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/launix-de/memcp&lt;br /&gt;
cd memcp&lt;br /&gt;
go get&lt;br /&gt;
make&lt;br /&gt;
pm2 start ./memcp ./data/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connect with MySQL tooling:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p -P 3307&lt;br /&gt;
Enter password: admin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== MemCP vs. MySQL ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature&lt;br /&gt;
! MySQL&lt;br /&gt;
! MemCP&lt;br /&gt;
|-&lt;br /&gt;
| Storage Model&lt;br /&gt;
| Row-based&lt;br /&gt;
| Column-based (compressed)&lt;br /&gt;
|-&lt;br /&gt;
| Performance&lt;br /&gt;
| Good&lt;br /&gt;
| NUMA-optimized, in-memory&lt;br /&gt;
|-&lt;br /&gt;
| In-Memory Capable&lt;br /&gt;
| Limited&lt;br /&gt;
| Yes (default)&lt;br /&gt;
|-&lt;br /&gt;
| REST API Integration&lt;br /&gt;
| External&lt;br /&gt;
| Built-in&lt;br /&gt;
|-&lt;br /&gt;
| Installation Footprint&lt;br /&gt;
| ~150MB+&lt;br /&gt;
| ~10MB&lt;br /&gt;
|-&lt;br /&gt;
| Open Source&lt;br /&gt;
| ✅&lt;br /&gt;
| ✅&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tables, Schemas, Columns&#039;&#039;&#039;: Familiar SQL-style structures with a columnar physical layout.  &lt;br /&gt;
* &#039;&#039;&#039;Transaction Model&#039;&#039;&#039;: Supports both OLTP and OLAP semantics with delta + main storage.  &lt;br /&gt;
* &#039;&#039;&#039;Persistence&#039;&#039;&#039;: Configurable storage backends (filesystem, S3, Ceph).  &lt;br /&gt;
* &#039;&#039;&#039;Frontends&#039;&#039;&#039;: Multiple query interfaces:&lt;br /&gt;
  - SQL frontend (MySQL wire protocol + SQL over REST)  &lt;br /&gt;
  - RDF/graph query engine  &lt;br /&gt;
  - Custom APIs via in-database web apps  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
* [[What is OLTP and OLAP]]  &lt;br /&gt;
* [[History of the MemCP project]]  &lt;br /&gt;
* [[Hardware Requirements]]  &lt;br /&gt;
* [[Persistency and Performance Guarantees]]  &lt;br /&gt;
* [[Comparison: MemCP vs. MySQL]]  &lt;br /&gt;
* [[Install MemCP with Docker|Install with Docker]]  &lt;br /&gt;
* [[Compile MemCP from Source|Build from Source]]  &lt;br /&gt;
* [[Contributing]]  &lt;br /&gt;
* [[SQL over REST]]  &lt;br /&gt;
* [[In-Database WebApps|REST &amp;amp; Microservices]]  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Navigation===&lt;br /&gt;
&lt;br /&gt;
====Introduction==== &lt;br /&gt;
*[[What is OLTP and OLAP]]&lt;br /&gt;
*[[History of the MemCP project]]&lt;br /&gt;
*[[Hardware Requirements]]&lt;br /&gt;
*[[Persistency and Performance Guarantees]] &lt;br /&gt;
*[[Current Status and Open Issues]]&lt;br /&gt;
*[[Comparison: MemCP vs. MySQL]]&lt;br /&gt;
&lt;br /&gt;
====Getting Started====&lt;br /&gt;
*[[Install MemCP with Docker|With Docker]]&lt;br /&gt;
*[[With Singularity]]&lt;br /&gt;
*[[Compile MemCP from Source|Build from Source]]&lt;br /&gt;
*[[Contributing]] &lt;br /&gt;
*[[Introduction to Scheme]]&lt;br /&gt;
*[[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
====Administration====&lt;br /&gt;
&lt;br /&gt;
* [[Deployment]]&lt;br /&gt;
* [[Migration from MySQL and PostgreSQL]]&lt;br /&gt;
* [[Settings]]&lt;br /&gt;
*[[Process Hibernation]]&lt;br /&gt;
*[[Performance Measurement]]&lt;br /&gt;
*[[MemCP Console]]&lt;br /&gt;
*[[Performance Measurement]]&lt;br /&gt;
&lt;br /&gt;
====Frontends====&lt;br /&gt;
&lt;br /&gt;
=====SQL Frontend===== &lt;br /&gt;
*[[Supported SQL]]&lt;br /&gt;
*[[Advanced SQL Tutorial]]&lt;br /&gt;
*[[SQL over REST]]&lt;br /&gt;
*[[Database Tools compatibility with MemCP|Supported Tooling]]&lt;br /&gt;
*[[How SQL Operators are implemented on MemCP]]&lt;br /&gt;
*[[Add custom SQL operators to MemCP]]&lt;br /&gt;
&lt;br /&gt;
=====RDF Frontend===== &lt;br /&gt;
*[[Introduction to RDF]]&lt;br /&gt;
*[[Advanced Graph Querying]]&lt;br /&gt;
*[[RDF templating and model driven development]]&lt;br /&gt;
&lt;br /&gt;
=====Custom Frontends=====&lt;br /&gt;
&lt;br /&gt;
*[[In-Database WebApps|In-Database WebApps and REST Services]]&lt;br /&gt;
*[[MemCP for Microservices]]&lt;br /&gt;
*[[Websockets in MemCP]]&lt;br /&gt;
&lt;br /&gt;
==== Persistency Backends (= Storage) ====&lt;br /&gt;
&lt;br /&gt;
* [[File System]]&lt;br /&gt;
* [[S3 Buckets]]&lt;br /&gt;
* [[Ceph/Rados]]&lt;br /&gt;
* [[Cluster Monitor]]&lt;br /&gt;
&lt;br /&gt;
====Internals====&lt;br /&gt;
&lt;br /&gt;
=====How things work in MemCP===== &lt;br /&gt;
&lt;br /&gt;
*[[Databases, Tables and Columns]]&lt;br /&gt;
*[[Shards, RecordIDs, Main Storage, Delta Storage]]&lt;br /&gt;
*[[Columnar Storage]]&lt;br /&gt;
*[[Transactions and Isolation]]&lt;br /&gt;
*[[Full SCM API documentation]] &lt;br /&gt;
*[[Query Planner and Physical Lowering]] &lt;br /&gt;
&lt;br /&gt;
===== SCM Documentation =====&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
&lt;br /&gt;
=====Optimizations=====&lt;br /&gt;
*[[In-Memory Compression, Columnar Compression Techniques]]&lt;br /&gt;
*[[Temporary Columns]]&lt;br /&gt;
*[[Data Auto Sharding and Auto Indexing]]&lt;br /&gt;
* [[Parallel Computing]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Further Reading ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.org/launix-de/memcp MemCP on GitHub]  &lt;br /&gt;
* [https://www.vldb.org/pvldb/vol13/p2649-boncz.pdf VLDB Research Paper]  &lt;br /&gt;
* [https://cs.emis.de/LNI/Proceedings/Proceedings241/383.pdf LNI Proceedings Paper]  &lt;br /&gt;
* [https://www.dcs.bbk.ac.uk/~dell/teaching/cc/paper/sigmod10/p135-malewicz.pdf Large Graph Algorithms]  &lt;br /&gt;
&lt;br /&gt;
Additional blog posts on design decisions, compression techniques, and performance optimization are available on the [https://launix.de/launix/ Launix blog].&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
&lt;br /&gt;
MemCP is an open-source project maintained by developers for developers.  &lt;br /&gt;
Contributions are welcome — whether in the form of bug reports, feature requests, or pull requests.  &lt;br /&gt;
&lt;br /&gt;
See: [[Contributing]]&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Main_Page&amp;diff=269</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Main_Page&amp;diff=269"/>
		<updated>2026-08-21T11:18:36Z</updated>

		<summary type="html">&lt;p&gt;Carli: /* Navigation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= MemCP – A Modern In-Memory Columnar Database =&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;MemCP is a high-performance, in-memory, column-oriented database designed for modern workloads.&#039;&#039;&#039;  &lt;br /&gt;
It provides a lightweight, developer-friendly alternative to traditional relational databases such as MySQL, with a focus on speed, compression, and direct API integration.&lt;br /&gt;
[[File:Memcp-Load.png|center|frameless|1600x1600px]]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Key Features ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;High Performance&#039;&#039;&#039;: NUMA-aware, parallelized query execution optimized for multicore CPUs, large caches, and NVMe SSDs. Handles both OLTP and OLAP workloads efficiently.  &lt;br /&gt;
* &#039;&#039;&#039;Columnar Storage&#039;&#039;&#039;: Data is stored by column for improved compression, reduced memory footprint, and faster analytical queries.  &lt;br /&gt;
* &#039;&#039;&#039;In-Memory Operation&#039;&#039;&#039;: Designed to keep data in memory, with configurable persistence backends for durability.  &lt;br /&gt;
* &#039;&#039;&#039;Built-in APIs&#039;&#039;&#039;: Exposes RESTful endpoints directly from the database, reducing middleware overhead.  &lt;br /&gt;
* &#039;&#039;&#039;Compression&#039;&#039;&#039;: Multiple strategies (bit-packing, dictionary encoding, sequence compression) reduce storage by up to 80% compared to MySQL/MariaDB.  &lt;br /&gt;
* &#039;&#039;&#039;Simple Deployment&#039;&#039;&#039;: Start with a single &amp;lt;code&amp;gt;docker run&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;pm2 start&amp;lt;/code&amp;gt; command. Lightweight footprint (~10MB).  &lt;br /&gt;
* &#039;&#039;&#039;Extensible&#039;&#039;&#039;: Written in Go, with pluggable storage backends and custom frontend support (SQL, RDF, REST).  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Why MemCP? ==&lt;br /&gt;
&lt;br /&gt;
Traditional relational databases were designed decades ago, optimized for spinning disks and single-core CPUs.  &lt;br /&gt;
MemCP rethinks the core design for today’s hardware and workloads:&lt;br /&gt;
&lt;br /&gt;
* Real-time dashboards and analytics  &lt;br /&gt;
* Data-heavy SaaS platforms  &lt;br /&gt;
* Embedded systems with limited resources  &lt;br /&gt;
* High-throughput OLTP/OLAP hybrids  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Quick Start ==&lt;br /&gt;
&lt;br /&gt;
Clone and build MemCP from source:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
git clone https://github.com/launix-de/memcp&lt;br /&gt;
cd memcp&lt;br /&gt;
go get&lt;br /&gt;
make&lt;br /&gt;
pm2 start ./memcp ./data/&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Connect with MySQL tooling:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
mysql -u root -p -P 3307&lt;br /&gt;
Enter password: admin&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== MemCP vs. MySQL ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Feature&lt;br /&gt;
! MySQL&lt;br /&gt;
! MemCP&lt;br /&gt;
|-&lt;br /&gt;
| Storage Model&lt;br /&gt;
| Row-based&lt;br /&gt;
| Column-based (compressed)&lt;br /&gt;
|-&lt;br /&gt;
| Performance&lt;br /&gt;
| Good&lt;br /&gt;
| NUMA-optimized, in-memory&lt;br /&gt;
|-&lt;br /&gt;
| In-Memory Capable&lt;br /&gt;
| Limited&lt;br /&gt;
| Yes (default)&lt;br /&gt;
|-&lt;br /&gt;
| REST API Integration&lt;br /&gt;
| External&lt;br /&gt;
| Built-in&lt;br /&gt;
|-&lt;br /&gt;
| Installation Footprint&lt;br /&gt;
| ~150MB+&lt;br /&gt;
| ~10MB&lt;br /&gt;
|-&lt;br /&gt;
| Open Source&lt;br /&gt;
| ✅&lt;br /&gt;
| ✅&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Architecture Overview ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Tables, Schemas, Columns&#039;&#039;&#039;: Familiar SQL-style structures with a columnar physical layout.  &lt;br /&gt;
* &#039;&#039;&#039;Transaction Model&#039;&#039;&#039;: Supports both OLTP and OLAP semantics with delta + main storage.  &lt;br /&gt;
* &#039;&#039;&#039;Persistence&#039;&#039;&#039;: Configurable storage backends (filesystem, S3, Ceph).  &lt;br /&gt;
* &#039;&#039;&#039;Frontends&#039;&#039;&#039;: Multiple query interfaces:&lt;br /&gt;
  - SQL frontend (MySQL wire protocol + SQL over REST)  &lt;br /&gt;
  - RDF/graph query engine  &lt;br /&gt;
  - Custom APIs via in-database web apps  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Documentation ==&lt;br /&gt;
&lt;br /&gt;
* [[What is OLTP and OLAP]]  &lt;br /&gt;
* [[History of the MemCP project]]  &lt;br /&gt;
* [[Hardware Requirements]]  &lt;br /&gt;
* [[Persistency and Performance Guarantees]]  &lt;br /&gt;
* [[Comparison: MemCP vs. MySQL]]  &lt;br /&gt;
* [[Install MemCP with Docker|Install with Docker]]  &lt;br /&gt;
* [[Compile MemCP from Source|Build from Source]]  &lt;br /&gt;
* [[Contributing]]  &lt;br /&gt;
* [[SQL over REST]]  &lt;br /&gt;
* [[In-Database WebApps|REST &amp;amp; Microservices]]  &lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Navigation===&lt;br /&gt;
&lt;br /&gt;
====Introduction==== &lt;br /&gt;
*[[What is OLTP and OLAP]]&lt;br /&gt;
*[[History of the MemCP project]]&lt;br /&gt;
*[[Hardware Requirements]]&lt;br /&gt;
*[[Persistency and Performance Guarantees]] &lt;br /&gt;
*[[Current Status and Open Issues]]&lt;br /&gt;
*[[Comparison: MemCP vs. MySQL]]&lt;br /&gt;
&lt;br /&gt;
====Getting Started====&lt;br /&gt;
*[[Install MemCP with Docker|With Docker]]&lt;br /&gt;
*[[With Singularity]]&lt;br /&gt;
*[[Compile MemCP from Source|Build from Source]]&lt;br /&gt;
*[[Contributing]] &lt;br /&gt;
*[[Introduction to Scheme]]&lt;br /&gt;
*[[Full SCM API documentation]]&lt;br /&gt;
&lt;br /&gt;
====Administration====&lt;br /&gt;
&lt;br /&gt;
* [[Deployment]]&lt;br /&gt;
* [[Migration from MySQL and PostgreSQL]]&lt;br /&gt;
* [[Settings]]&lt;br /&gt;
*[[Process Hibernation]]&lt;br /&gt;
*[[Performance Measurement]]&lt;br /&gt;
*[[MemCP Console]]&lt;br /&gt;
*[[Performance Measurement]]&lt;br /&gt;
&lt;br /&gt;
====Frontends====&lt;br /&gt;
&lt;br /&gt;
=====SQL Frontend===== &lt;br /&gt;
*[[Supported SQL]]&lt;br /&gt;
*[[Advanced SQL Tutorial]]&lt;br /&gt;
*[[SQL over REST]]&lt;br /&gt;
*[[Database Tools compatibility with MemCP|Supported Tooling]]&lt;br /&gt;
*[[How SQL Operators are implemented on MemCP]]&lt;br /&gt;
*[[Add custom SQL operators to MemCP]]&lt;br /&gt;
&lt;br /&gt;
=====RDF Frontend===== &lt;br /&gt;
*[[Introduction to RDF]]&lt;br /&gt;
*[[Advanced Graph Querying]]&lt;br /&gt;
*[[RDF templating and model driven development]]&lt;br /&gt;
&lt;br /&gt;
=====Custom Frontends=====&lt;br /&gt;
&lt;br /&gt;
*[[In-Database WebApps|In-Database WebApps and REST Services]]&lt;br /&gt;
*[[MemCP for Microservices]]&lt;br /&gt;
*[[Websockets in MemCP]]&lt;br /&gt;
&lt;br /&gt;
==== Persistency Backends (= Storage) ====&lt;br /&gt;
&lt;br /&gt;
* [[File System]]&lt;br /&gt;
* [[S3 Buckets]]&lt;br /&gt;
* [[Ceph/Rados]]&lt;br /&gt;
* [[Cluster Monitor]]&lt;br /&gt;
&lt;br /&gt;
====Internals====&lt;br /&gt;
&lt;br /&gt;
=====How things work in MemCP===== &lt;br /&gt;
&lt;br /&gt;
*[[Databases, Tables and Columns]]&lt;br /&gt;
*[[Shards, RecordIDs, Main Storage, Delta Storage]]&lt;br /&gt;
*[[Columnar Storage]]&lt;br /&gt;
*[[Transactions and Isolation]]&lt;br /&gt;
*[[Full SCM API documentation]] &lt;br /&gt;
*[[Query Planner and Physical Lowering]] &lt;br /&gt;
&lt;br /&gt;
===== SCM Documentation =====&lt;br /&gt;
&lt;br /&gt;
* [[SCM Builtins]]&lt;br /&gt;
* [[Arithmetic / Logic]]&lt;br /&gt;
* [[Strings]]&lt;br /&gt;
* [[Streams]]&lt;br /&gt;
* [[Lists]]&lt;br /&gt;
* [[Associative Lists / Dictionaries]]&lt;br /&gt;
* [[Date]]&lt;br /&gt;
* [[Vectors]]&lt;br /&gt;
* [[Parsers]]&lt;br /&gt;
* [[Sync]]&lt;br /&gt;
* [[IO]]&lt;br /&gt;
* [[Storage]]&lt;br /&gt;
&lt;br /&gt;
=====Optimizations=====&lt;br /&gt;
*[[In-Memory Compression, Columnar Compression Techniques]]&lt;br /&gt;
*[[Temporary Columns]]&lt;br /&gt;
*[[Data Auto Sharding and Auto Indexing]]&lt;br /&gt;
* [[Parallel Computing]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Further Reading ==&lt;br /&gt;
&lt;br /&gt;
* [https://github.org/launix-de/memcp MemCP on GitHub]  &lt;br /&gt;
* [https://www.vldb.org/pvldb/vol13/p2649-boncz.pdf VLDB Research Paper]  &lt;br /&gt;
* [https://cs.emis.de/LNI/Proceedings/Proceedings241/383.pdf LNI Proceedings Paper]  &lt;br /&gt;
* [https://www.dcs.bbk.ac.uk/~dell/teaching/cc/paper/sigmod10/p135-malewicz.pdf Large Graph Algorithms]  &lt;br /&gt;
&lt;br /&gt;
Additional blog posts on design decisions, compression techniques, and performance optimization are available on the [https://launix.de/launix/ Launix blog].&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Community ==&lt;br /&gt;
&lt;br /&gt;
MemCP is an open-source project maintained by developers for developers.  &lt;br /&gt;
Contributions are welcome — whether in the form of bug reports, feature requests, or pull requests.  &lt;br /&gt;
&lt;br /&gt;
See: [[Contributing]]&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Dashboard_and_Operations&amp;diff=268</id>
		<title>Dashboard and Operations</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Dashboard_and_Operations&amp;diff=268"/>
		<updated>2026-08-21T11:04:48Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot;The &amp;lt;code&amp;gt;/dashboard&amp;lt;/code&amp;gt; interface provides CPU/memory/request metrics, database and table browsing, shard/compression details, SQL/Scheme consoles, users and grants, runtime settings, process inspection, service state, and configured logs.  &amp;lt;code&amp;gt;SHOW [FULL] PROCESSLIST&amp;lt;/code&amp;gt;, dashboard process controls, &amp;lt;code&amp;gt;KILL QUERY&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;KILL CONNECTION&amp;lt;/code&amp;gt; expose active work and cancellation. Graceful shutdown stops new requests and waits up to &amp;lt;code&amp;gt;ShutdownDr...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The &amp;lt;code&amp;gt;/dashboard&amp;lt;/code&amp;gt; interface provides CPU/memory/request metrics, database and table browsing, shard/compression details, SQL/Scheme consoles, users and grants, runtime settings, process inspection, service state, and configured logs.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;SHOW [FULL] PROCESSLIST&amp;lt;/code&amp;gt;, dashboard process controls, &amp;lt;code&amp;gt;KILL QUERY&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;KILL CONNECTION&amp;lt;/code&amp;gt; expose active work and cancellation. Graceful shutdown stops new requests and waits up to &amp;lt;code&amp;gt;ShutdownDrainSeconds&amp;lt;/code&amp;gt; for in-flight work.&lt;br /&gt;
&lt;br /&gt;
Optional &amp;lt;code&amp;gt;MetricsTracing&amp;lt;/code&amp;gt; writes periodic samples. &amp;lt;code&amp;gt;ErrorQueryLog&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;PrintLog&amp;lt;/code&amp;gt; store failed SQL and Scheme print/time output with configurable retention limits. These logs may contain SQL text or application data; restrict access and set appropriate limits.&lt;br /&gt;
&lt;br /&gt;
Protect the dashboard with a strong password and network controls. Do not use it as a substitute for backups, external health checks, alerting, or backend monitoring. Watch memory budgets, errors, active requests, WAL/rebuild behavior, remote-storage latency, and restart validation.&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Triggers&amp;diff=267</id>
		<title>Triggers</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Triggers&amp;diff=267"/>
		<updated>2026-08-21T11:03:47Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot;MemCP supports persistent BEFORE and AFTER triggers for INSERT, UPDATE, and DELETE. Trigger bodies can read &amp;lt;code&amp;gt;OLD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;NEW&amp;lt;&amp;lt;/code&amp;gt;, assign permitted &amp;lt;code&amp;gt;NEW&amp;lt;/code&amp;gt; values, run conditional BEGIN/END bodies, and execute supported DML including &amp;lt;code&amp;gt;INSERT … SELECT&amp;lt;/code&amp;gt;.  Multiple triggers execute by registered priority. AFTER work may be configured as asynchronous, in which case its completion and failure are not identical to the originating statemen...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;MemCP supports persistent BEFORE and AFTER triggers for INSERT, UPDATE, and DELETE. Trigger bodies can read &amp;lt;code&amp;gt;OLD&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;NEW&amp;lt;&amp;lt;/code&amp;gt;, assign permitted &amp;lt;code&amp;gt;NEW&amp;lt;/code&amp;gt; values, run conditional BEGIN/END bodies, and execute supported DML including &amp;lt;code&amp;gt;INSERT … SELECT&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Multiple triggers execute by registered priority. AFTER work may be configured as asynchronous, in which case its completion and failure are not identical to the originating statement&#039;s synchronous path. Trigger changes participate in transaction/savepoint recovery.&lt;br /&gt;
&lt;br /&gt;
MemCP also uses hidden system triggers to enforce constraints and maintain computed columns, group caches, prejoins, and invalidation dependencies. User DROP/CASCADE behavior must not delete unrelated data; lifecycle callbacks are not general garbage collectors.&lt;br /&gt;
&lt;br /&gt;
Test trigger persistence across restart, multi-row statements, NULL/default handling, errors, ordering, cross-table writes, and rollback. Recursive trigger graphs should be treated with particular care.&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Memory_Management_and_Eviction&amp;diff=266</id>
		<title>Memory Management and Eviction</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Memory_Management_and_Eviction&amp;diff=266"/>
		<updated>2026-08-21T11:02:20Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot;MemCP tracks persisted shard columns, indexes, temporary columns, keytables, cache-engine objects, and string dictionaries in a global memory manager.  The overall budget defaults to 50% of system RAM. A separate persisted-data budget defaults to 30%. Exact byte limits override percentages. If system available memory falls too low, MemCP can evict before its own configured budget is exhausted.  Eviction is LRU-like and type-aware. Persistent shard eviction releases only...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;MemCP tracks persisted shard columns, indexes, temporary columns, keytables, cache-engine objects, and string dictionaries in a global memory manager.&lt;br /&gt;
&lt;br /&gt;
The overall budget defaults to 50% of system RAM. A separate persisted-data budget defaults to 30%. Exact byte limits override percentages. If system available memory falls too low, MemCP can evict before its own configured budget is exhausted.&lt;br /&gt;
&lt;br /&gt;
Eviction is LRU-like and type-aware. Persistent shard eviction releases only in-memory representations; files remain and are reloaded on demand. Shards with unflushed deltas cannot be evicted. &amp;lt;code&amp;gt;memory&amp;lt;/code&amp;gt; tables are never evicted because that would destroy their only copy. &amp;lt;code&amp;gt;cache&amp;lt;/code&amp;gt; tables are explicitly reconstructible and may be discarded under pressure.&lt;br /&gt;
&lt;br /&gt;
Monitor both current/budgeted memory and reload behavior. A workload whose hot set exceeds the budget remains correct for persistent tables but may become storage-I/O bound. See [[Settings]] and [[Dashboard_and_Operations|Dashboard and Operations]].&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Transactions_and_Isolation&amp;diff=265</id>
		<title>Transactions and Isolation</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Transactions_and_Isolation&amp;diff=265"/>
		<updated>2026-08-21T11:01:00Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot;Every SQL statement runs in an implicit transaction unless the session already has an explicit &amp;lt;code&amp;gt;BEGIN&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;COMMIT&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;ROLLBACK&amp;lt;/code&amp;gt; transaction.  The default cursor-stability mode applies writes directly with undo masks, gives statement atomicity, and rolls back on errors. MemCP also contains an ACID mode with snapshot visibility and optimistic commit conflict detection. Savepoints are used internally for nested trigger/error recovery.  Transactio...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Every SQL statement runs in an implicit transaction unless the session already has an explicit &amp;lt;code&amp;gt;BEGIN&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;COMMIT&amp;lt;/code&amp;gt;/&amp;lt;code&amp;gt;ROLLBACK&amp;lt;/code&amp;gt; transaction.&lt;br /&gt;
&lt;br /&gt;
The default cursor-stability mode applies writes directly with undo masks, gives statement atomicity, and rolls back on errors. MemCP also contains an ACID mode with snapshot visibility and optimistic commit conflict detection. Savepoints are used internally for nested trigger/error recovery.&lt;br /&gt;
&lt;br /&gt;
Transaction state is tracked per shard. Visibility includes main rows, delta rows, insert/delete overlays, transaction snapshot, and the active shard generation. Commit locks and publishes touched shards; rollback reverses staged or directly applied changes. Nested shard work has a bounded fanout to avoid deadlock and goroutine explosion.&lt;br /&gt;
&lt;br /&gt;
For &amp;lt;code&amp;gt;safe&amp;lt;/code&amp;gt; tables, WAL synchronization occurs at commit. &amp;lt;code&amp;gt;logged&amp;lt;/code&amp;gt; writes WAL without fsync; &amp;lt;code&amp;gt;sloppy&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;memory&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;cache&amp;lt;/code&amp;gt; skip WAL durability. A transaction spanning tables therefore inherits the guarantees and risks of each table&#039;s ENGINE.&lt;br /&gt;
&lt;br /&gt;
MemCP does not claim every MySQL isolation level, XA, or distributed transaction feature. Test conflicts and failure recovery required by the application.&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Query_Planner_and_Physical_Lowering&amp;diff=264</id>
		<title>Query Planner and Physical Lowering</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Query_Planner_and_Physical_Lowering&amp;diff=264"/>
		<updated>2026-08-21T10:58:02Z</updated>

		<summary type="html">&lt;p&gt;Carli: Created page with &amp;quot;MemCP compiles SQL into executable Scheme code. The planner first converts SQL into a logical representation, decorrelates subqueries, and chooses a join order. Only after those semantic decisions are complete does the physical lowerer select scans, indexes, caches, RecSets, computed columns, and other storage-engine operators.  This separation is important: two queries that mean the same thing should reach the same logical representation even when they use different...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;MemCP compiles SQL into executable Scheme code. The planner first converts SQL into a logical representation, decorrelates subqueries, and chooses a join order. Only after those semantic decisions are complete does the physical lowerer select scans, indexes, caches, [[RecSets]], computed columns, and other storage-engine operators.&lt;br /&gt;
&lt;br /&gt;
This separation is important: two queries that mean the same thing should reach the same logical representation even when they use different SQL spelling. The physical plan can then be chosen from statistics, parameters, ordering, limits, and the state of reusable intermediate relations.&lt;br /&gt;
==Planner pipeline==&lt;br /&gt;
  -&amp;gt; MySQL or PostgreSQL parser AST&lt;br /&gt;
  -&amp;gt; normalize_sql_syntax&lt;br /&gt;
  -&amp;gt; decorrelate_logical_query / untangle_query&lt;br /&gt;
  -&amp;gt; logical predicate placement and join_reorder / optimize&lt;br /&gt;
  -&amp;gt; build_queryplan&lt;br /&gt;
  -&amp;gt; Scheme optimizer and optional native JIT&lt;br /&gt;
  -&amp;gt; storage-engine scans&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Each phase owns a different kind of decision:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Phase&lt;br /&gt;
!Responsibility&lt;br /&gt;
|-&lt;br /&gt;
|Parser&lt;br /&gt;
|Preserve SQL structure and produce neutral query terms.&lt;br /&gt;
|-&lt;br /&gt;
|Normalization&lt;br /&gt;
|Remove parser-specific spelling and safe syntactic sugar while preserving SQL three-valued logic.&lt;br /&gt;
|-&lt;br /&gt;
|Decorrelation&lt;br /&gt;
|Replace dependent subqueries with explicit domains, stages, keys, and joins.&lt;br /&gt;
|-&lt;br /&gt;
|Logical optimization&lt;br /&gt;
|Place predicates across proven-safe boundaries, estimate cardinalities and selectivities, and choose the join tree.&lt;br /&gt;
|-&lt;br /&gt;
|Physical lowering&lt;br /&gt;
|Select concrete scan sources and operators, bind predicates to scans, and emit Scheme code.&lt;br /&gt;
|-&lt;br /&gt;
|Scheme optimization/JIT&lt;br /&gt;
|Optimize the emitted functional program and compile supported hot paths to native code.&lt;br /&gt;
|}Physical objects such as &amp;lt;code&amp;gt;scan&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;scan_order&amp;lt;/code&amp;gt;, RecSets, keytables, ORC columns, and temporary tables must not leak into the logical representation. Conversely, the physical lowerer must not redo decorrelation or silently choose a different join order.&lt;br /&gt;
==Logical representation==&lt;br /&gt;
MemCP deliberately uses three coarse combined operator shapes instead of a long chain of textbook relational operators:&lt;br /&gt;
*&amp;lt;code&amp;gt;query-block&amp;lt;/code&amp;gt; represents SELECT, JOIN, filter, projection, order, limit, and offset work.&lt;br /&gt;
*&amp;lt;code&amp;gt;group-stage&amp;lt;/code&amp;gt; represents grouping, aggregates, correlated domains, EXISTS/IN/scalar helpers, HAVING, and window-partition work.&lt;br /&gt;
*&amp;lt;code&amp;gt;union-block&amp;lt;/code&amp;gt; represents &amp;lt;code&amp;gt;UNION&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;UNION ALL&amp;lt;/code&amp;gt;.&lt;br /&gt;
A &amp;lt;code&amp;gt;stage-output&amp;lt;/code&amp;gt; describes the logical relation produced by a group or union stage. It is not a physical table and does not prescribe how the result will be stored or scanned.&lt;br /&gt;
&lt;br /&gt;
This combined model keeps related operations together so the physical engine can fuse them into one scan where possible. Splitting every filter, projection, and limit into a separate logical node would introduce artificial materialization boundaries and make later rewrites more expensive.&lt;br /&gt;
==Subquery decorrelation==&lt;br /&gt;
MemCP does not execute a correlated subquery once for every outer row as a fallback. Supported correlated forms are decorrelated into relational stages. Unsupported shapes fail explicitly instead of silently selecting a slow or semantically weaker execution path.&lt;br /&gt;
&lt;br /&gt;
The planner first tries simple unnesting:&lt;br /&gt;
#collect equality classes;&lt;br /&gt;
#choose safe representative expressions;&lt;br /&gt;
#pull predicates and projections across valid boundaries;&lt;br /&gt;
#convert trivial dependent joins into ordinary joins.&lt;br /&gt;
If dependencies remain, the planner builds Neumann&#039;s &#039;&#039;&#039;Domain D&#039;&#039;&#039;: the duplicate-free projection of the outer values actually read by the dependent subtree. Domain keys are carried through the inner stages and joined back to the outer query. This supports correlated scalar subqueries, &amp;lt;code&amp;gt;EXISTS&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt;, grouped subqueries, HAVING, derived tables, and window expressions without per-row recursive SQL execution.&lt;br /&gt;
&lt;br /&gt;
The logical stage also preserves semantic details that must survive lowering:&lt;br /&gt;
*scalar subquery cardinality: ordinary relation, first row, or single row with an error on the second row;&lt;br /&gt;
*SQL NULL behavior for &amp;lt;code&amp;gt;IN&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;NOT IN&amp;lt;/code&amp;gt;;&lt;br /&gt;
*empty correlated aggregate domains, including &amp;lt;code&amp;gt;COUNT = 0&amp;lt;/code&amp;gt; versus nullable aggregates;&lt;br /&gt;
*outer-join null-extension boundaries;&lt;br /&gt;
*ordering, limit, and window requirements.&lt;br /&gt;
==Join ordering==&lt;br /&gt;
Join ordering is a logical decision with one owner. After decorrelation exposes the complete join graph, &amp;lt;code&amp;gt;join_reorder&amp;lt;/code&amp;gt; uses cardinality and selectivity facts to choose a join tree. The search can use exact DPHyp-style enumeration within the configured budget and fall back to bounded strategies for larger join graphs.&lt;br /&gt;
&lt;br /&gt;
The selected tree can be bushy. Physical lowering consumes that tree structurally; it may not flatten the leaves and make a second order decision. Each join node retains:&lt;br /&gt;
*its left and right subtrees;&lt;br /&gt;
*join kind;&lt;br /&gt;
*bound aliases;&lt;br /&gt;
*ON-clause ownership;&lt;br /&gt;
*null-extension boundary;&lt;br /&gt;
*predicates already classified and costed for a leaf.&lt;br /&gt;
Independent subtrees may run in parallel. Dependent subtrees remain ordered by their bindings. This execution choice does not change the logical join order.&lt;br /&gt;
&lt;br /&gt;
The exact-search budget can be inspected or changed through:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;(settings &amp;quot;JoinReorderDPBudget&amp;quot;) (settings &amp;quot;JoinReorderDPBudget&amp;quot; 256)&amp;lt;/code&amp;gt;&lt;br /&gt;
==Cost-based physical lowering==&lt;br /&gt;
The physical lowerer answers a different question from join ordering: given the chosen logical stage and join tree, which concrete storage-engine representation and operator is cheapest while preserving its semantics?&lt;br /&gt;
&lt;br /&gt;
The cost model can consider:&lt;br /&gt;
*base-table, stage, and probe cardinality;&lt;br /&gt;
*filter selectivity and distinct key counts;&lt;br /&gt;
*scan and probe work estimates;&lt;br /&gt;
*order compatibility, offset, and limit;&lt;br /&gt;
*available and adaptive indexes;&lt;br /&gt;
*warm or cold state of reusable group caches;&lt;br /&gt;
*expected reuse count;&lt;br /&gt;
*build cost versus probe cost;&lt;br /&gt;
*memory footprint;&lt;br /&gt;
*compile-time cost;&lt;br /&gt;
*previous scan and intermediate-relation telemetry.&lt;br /&gt;
Depending on these facts, the same logical stage may lower differently:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Physical choice&lt;br /&gt;
!Typical use&lt;br /&gt;
|-&lt;br /&gt;
|Fused &amp;lt;code&amp;gt;scan&amp;lt;/code&amp;gt;&lt;br /&gt;
|Unordered filter, projection, and aggregation in one pass.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;scan_order&amp;lt;/code&amp;gt;&lt;br /&gt;
|Ordered access, top-k, offset/limit ownership, or a bounded scalar probe.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;scan_order_multi&amp;lt;/code&amp;gt;&lt;br /&gt;
|Merge already streamable ordered inputs, especially &amp;lt;code&amp;gt;UNION ALL&amp;lt;/code&amp;gt;.&lt;br /&gt;
|-&lt;br /&gt;
|&amp;lt;code&amp;gt;scan_exists&amp;lt;/code&amp;gt;&lt;br /&gt;
|Stop after proving that at least one matching row exists.&lt;br /&gt;
|-&lt;br /&gt;
|Direct nested scan&lt;br /&gt;
|Cheap selective lookup driven by already bound join keys.&lt;br /&gt;
|-&lt;br /&gt;
|[[RecSet]]&lt;br /&gt;
|Query-local set of matching record IDs for membership and boolean combinations.&lt;br /&gt;
|-&lt;br /&gt;
|[[RecSet]] projection&lt;br /&gt;
|Move a selective candidate set through join keys to another base relation.&lt;br /&gt;
|-&lt;br /&gt;
|Group keytable&lt;br /&gt;
|Reusable grouped key domain with computed aggregate columns.&lt;br /&gt;
|-&lt;br /&gt;
|FK-backed cached column&lt;br /&gt;
|Reuse a foreign-key-shaped lookup or aggregate result on the referencing relation.&lt;br /&gt;
|-&lt;br /&gt;
|ORC computed column&lt;br /&gt;
|Reusable order-dependent computation, including window work with dependency ranges.&lt;br /&gt;
|-&lt;br /&gt;
|Query-local temporary table&lt;br /&gt;
|Last-resort relational barrier when streaming or reusable representations do not fit.&lt;br /&gt;
|}Relational results stay inside the storage engine. They are not copied into Scheme lists merely to join, sort, limit, or probe them. Keeping them as scan sources preserves indexing, statistics, batch reads, range braking, late materialization, concurrency, and bounded memory behavior.&lt;br /&gt;
==RecSets and boolean predicates==&lt;br /&gt;
A RecSet is a query-local set of physical record IDs for one base relation and visibility snapshot. RecSets can represent exact truth sets or safe candidate sets that still require a residual SQL predicate.&lt;br /&gt;
&lt;br /&gt;
For truth-filtering contexts, the planner can use ordinary set identities:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;T(false)   = empty T(true)    = all visible rows T(p OR q)  = T(p) union T(q) T(p AND q) = T(p) intersect T(q)&amp;lt;/code&amp;gt; Current physical representations include sparse IDs and ranges, with optimized union, intersection, complement, difference, and cross-relation projection. The planner still compares RecSet work with direct scans, indexes, keytables, and ordered drivers; deriving a valid set expression does not force RecSet execution.&lt;br /&gt;
&lt;br /&gt;
SQL three-valued logic remains authoritative. In particular, complementing the TRUE rows of a nullable predicate is not generally equivalent to SQL &amp;lt;code&amp;gt;NOT&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;NOT IN&amp;lt;/code&amp;gt; must retain its distinction between a match, a NULL probe, and NULL on the right-hand side.&lt;br /&gt;
==LIMIT, UNION, and window pipelines==&lt;br /&gt;
&amp;lt;code&amp;gt;LIMIT&amp;lt;/code&amp;gt; is owned by a physical scan boundary. A plan does not first materialize all qualifying rows into a Scheme list and slice it later. &amp;lt;code&amp;gt;scan_order&amp;lt;/code&amp;gt; can own LIMIT even without an explicit &amp;lt;code&amp;gt;ORDER BY&amp;lt;/code&amp;gt;, allowing early termination and top-k behavior.&lt;br /&gt;
&lt;br /&gt;
For set operations, the preferred lowering is:&lt;br /&gt;
*unordered &amp;lt;code&amp;gt;UNION ALL&amp;lt;/code&amp;gt;: emit branches successively;&lt;br /&gt;
*unordered &amp;lt;code&amp;gt;UNION&amp;lt;/code&amp;gt;: use a deduplication barrier;&lt;br /&gt;
*ordered, streamable &amp;lt;code&amp;gt;UNION ALL&amp;lt;/code&amp;gt;: merge through &amp;lt;code&amp;gt;scan_order_multi&amp;lt;/code&amp;gt;;&lt;br /&gt;
*non-streamable ordered unions: materialize only the narrow relation required by the ordering barrier.&lt;br /&gt;
A window expression does not automatically force materialization. If one scan order satisfies the base query and every window partition/order, MemCP can fuse the window computation into that ordered scan. ORC or a window stage is used when orders conflict, results are shared, or an order-dependent value must be cached as a computed column.&lt;br /&gt;
==Planner cache and guarded specialization==&lt;br /&gt;
The query-plan cache and storage-engine group caches are separate:&lt;br /&gt;
*The query-plan cache stores compiled Scheme plan formulas for normalized SQL shapes.&lt;br /&gt;
*A group cache is a reusable storage-engine relation, normally represented by a group keytable with computed aggregate columns.&lt;br /&gt;
For a SELECT whose optimal physical plan depends on parameters or changing statistics, one cache entry may contain several guarded physical variants. A guard records the condition under which its plan remains valid. On a guard miss, MemCP compiles one new variant for the current parameter/statistics regime and places it before older variants.&lt;br /&gt;
&lt;br /&gt;
Guards repeat cost comparisons, not query planning. They do not scan tables, build indexes or caches, or materialize data. Queries without a cost-model tipping decision keep the smaller exact-cache path.&lt;br /&gt;
==Inspecting plans with EXPLAIN==&lt;br /&gt;
Both MySQL and PostgreSQL syntax modes expose planner diagnostics:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;EXPLAIN SELECT ...; EXPLAIN IR SELECT ...; EXPLAIN REORDER SELECT ...; EXPLAIN COMPILE SELECT ...;&amp;lt;/code&amp;gt;&lt;br /&gt;
*&amp;lt;code&amp;gt;EXPLAIN&amp;lt;/code&amp;gt; shows the optimized executable Scheme plan.&lt;br /&gt;
*&amp;lt;code&amp;gt;EXPLAIN IR&amp;lt;/code&amp;gt; shows the logical representation before physical emission.&lt;br /&gt;
*&amp;lt;code&amp;gt;EXPLAIN REORDER&amp;lt;/code&amp;gt; exposes join-reordering information and selectivity facts.&lt;br /&gt;
*&amp;lt;code&amp;gt;EXPLAIN COMPILE&amp;lt;/code&amp;gt; reports compile-phase accounting, including parsing, logical work, reordering, physical preparation, emission, and optimization.&lt;br /&gt;
*&amp;lt;code&amp;gt;EXPLAIN PHYSICAL&amp;lt;/code&amp;gt; reports plan operator decisions along with query runtime predictions.&lt;br /&gt;
Important physical choices should be visible in EXPLAIN output so plan-shape tests can protect them against regressions. Pretty-print width is controlled by:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;(settings &amp;quot;ExplainWidth&amp;quot; 80)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For scan and adaptive-index diagnostics, development environments can also use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;(settings &amp;quot;ScanDebugging&amp;quot; true)&amp;lt;/code&amp;gt;&lt;br /&gt;
==Adaptive indexes and physical plans==&lt;br /&gt;
Adaptive indexing belongs to storage access, not logical planning. Scan boundaries describe the desired equality, range, pattern, and ordering prefix. The storage engine can reuse a compatible longer index, avoid creating indexes for tiny shards, accumulate expected savings, and build an index when its cost is amortized.&lt;br /&gt;
&lt;br /&gt;
Main-storage and delta rows participate in ordered index scans. Delta rows are kept in an index-local ordered structure and merged with the compressed main permutation during iteration, so an ordered physical plan does not append delta rows out of order.&lt;br /&gt;
==Failure behavior and correctness boundaries==&lt;br /&gt;
The planner favors explicit failure over hidden fallback behavior. An unsupported correlated or physical shape should report that limitation. It must not silently:&lt;br /&gt;
*execute a correlated subquery once per outer row;&lt;br /&gt;
*discard residual predicates;&lt;br /&gt;
*turn an equijoin into a cross product;&lt;br /&gt;
*treat &amp;lt;code&amp;gt;NOT IN&amp;lt;/code&amp;gt; as two-valued logic;&lt;br /&gt;
*reduce scalar cardinality checks to &amp;lt;code&amp;gt;LIMIT 1&amp;lt;/code&amp;gt;;&lt;br /&gt;
*materialize an unbounded relation in a Scheme list;&lt;br /&gt;
*choose a second join order during physical lowering.&lt;br /&gt;
This rule keeps performance decisions separate from SQL correctness and makes missing optimizer cases visible in tests and issue reports.&lt;br /&gt;
==Terminology==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!Term&lt;br /&gt;
!Meaning&lt;br /&gt;
|-&lt;br /&gt;
|Logical stage&lt;br /&gt;
|Semantic query work independent of storage representation.&lt;br /&gt;
|-&lt;br /&gt;
|Scan source&lt;br /&gt;
|A storage-engine representation consumable by a physical scan.&lt;br /&gt;
|-&lt;br /&gt;
|Intermediate relation&lt;br /&gt;
|A relational result materialized as a scan source between plan stages.&lt;br /&gt;
|-&lt;br /&gt;
|Group cache&lt;br /&gt;
|A reusable intermediate relation for group keys and aggregates.&lt;br /&gt;
|-&lt;br /&gt;
|Group keytable&lt;br /&gt;
|The normal physical representation of a group cache.&lt;br /&gt;
|-&lt;br /&gt;
|ORC&lt;br /&gt;
|An order-dependent reusable computed column.&lt;br /&gt;
|-&lt;br /&gt;
|RecSet&lt;br /&gt;
|A query-local set or candidate set of record IDs for one base relation.&lt;br /&gt;
|-&lt;br /&gt;
|Physical lowering&lt;br /&gt;
|Selection of concrete scan sources/operators after logical planning.&lt;br /&gt;
|-&lt;br /&gt;
|Guarded specialization&lt;br /&gt;
|Multiple cost-guarded physical plans for one normalized SELECT shape.&lt;br /&gt;
|}&lt;br /&gt;
==Further reading==&lt;br /&gt;
*[[Data_Auto_Sharding_and_Auto_Indexing|Data Auto Sharding and Auto Indexing]]&lt;br /&gt;
*[[Temporary_Computed_Columns|Temporary Computed Columns]]&lt;br /&gt;
*[[Columnar_Storage|Columnar Storage]]&lt;br /&gt;
*[[Parallel_Computing|Parallel Computing]]&lt;br /&gt;
*MemCP source: &amp;lt;code&amp;gt;INVARIANTS.md&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;lib/queryplan.scm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;lib/sql-parser.scm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;lib/psql-parser.scm&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;storage/scan.go&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;storage/scan_order.go&amp;lt;/code&amp;gt;, and &amp;lt;code&amp;gt;storage/recset.go&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Persistency_and_Performance_Guarantees&amp;diff=263</id>
		<title>Persistency and Performance Guarantees</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Persistency_and_Performance_Guarantees&amp;diff=263"/>
		<updated>2026-03-09T12:20:19Z</updated>

		<summary type="html">&lt;p&gt;Carli: /* Persistency Guarantees */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;MemCP gives the user several Guarantees for persistency and performance. These are the guarantees:&lt;br /&gt;
&lt;br /&gt;
== Performance Guarantees and Read Speed ==&lt;br /&gt;
MemCP guarantees that:&lt;br /&gt;
&lt;br /&gt;
* All reading operations are from RAM and are fast&lt;br /&gt;
* Insert/Update without any unique key check or foreign key check will scale over shards&lt;br /&gt;
* Aggregate functions like SUM, AVG will scale perfectly with the amount of CPUs&lt;br /&gt;
&lt;br /&gt;
With these guarantees, you can add more CPU cores whenever you have more data to ensure the same query time even with growing data.&lt;br /&gt;
&lt;br /&gt;
Please consider that memory bandwith still might be a bottleneck. Even modern 128 core CPUs do not scale better than 8 cores for uncompressed data (usually 40 GiB/s bandwith on tested machines). &#039;&#039;&#039;MemCPs [[Columnar Storage]] scales beyond that limit.&#039;&#039;&#039;&lt;br /&gt;
== Persistency Guarantees and Write Speed ==&lt;br /&gt;
There are five persistency modes per table which are:&lt;br /&gt;
&lt;br /&gt;
* ENGINE = cache&lt;br /&gt;
* ENGINE = memory&lt;br /&gt;
* ENGINE = sloppy&lt;br /&gt;
* ENGINE = logged&lt;br /&gt;
* ENGINE = safe&lt;br /&gt;
In comparison to other RDBMs, MemCP can do this setting per table. MySQL/MariaDB for instance only allows a global setting which is sometimes not what you want.&lt;br /&gt;
&lt;br /&gt;
In short, these engines guarantee different performance:&lt;br /&gt;
&lt;br /&gt;
* cache+memory -&amp;gt; RAM speed, no persistency&lt;br /&gt;
* sloppy+logged -&amp;gt; HDD speed, persistency guarantees under circumstances&lt;br /&gt;
* safe -&amp;gt; Sync speed (slow) and persistency guarantees even in case of power outage during queries&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = cache ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory and only in memory&lt;br /&gt;
* in case of a crash, all data is gone&lt;br /&gt;
* in case the server is running out of RAM, the data can be deleted, too&lt;br /&gt;
* the schema is saved on disk&lt;br /&gt;
* after a recovery, the table starts empty&lt;br /&gt;
* fastest way to store data&lt;br /&gt;
* use it for session data, observer handles, caches and other data that can be recreated by the software&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = memory ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory and only in memory&lt;br /&gt;
* in case of a crash, all data is gone&lt;br /&gt;
* while the server is running, the data will be kept alive&lt;br /&gt;
* the schema is saved on disk&lt;br /&gt;
* after a recovery, the table starts empty&lt;br /&gt;
* fastest way to store data&lt;br /&gt;
* use it for session data, observer handles, caches and other data that can be recreated by the software&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = sloppy ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory&lt;br /&gt;
* the main storage is mirrored on disk&lt;br /&gt;
* the delta storage is RAM-only&lt;br /&gt;
* a main storage rebuild is triggered every 15 minutes, so data older than 15 minutes are guaranteed to be persistent&lt;br /&gt;
* in case of a crash, the delta storage is gone, the main storage is recovered&lt;br /&gt;
* after a recovery, some datasets or deletions that happend in the last 15 minutes before the crash may be gone&lt;br /&gt;
* extremely fast way to store data without the fear of losing them in normal operation&lt;br /&gt;
* use it for frequently updated tables with unimportant data like usage statistics or sensor data&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = logged ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory&lt;br /&gt;
* the main storage is mirrored on disk&lt;br /&gt;
* changes to the delta storage are logged on disk files&lt;br /&gt;
* an operation succeeds even if data is not synced to disk permanently yet&lt;br /&gt;
* in case of a crash, data might be recovered&lt;br /&gt;
** in case of a crash of the process, all data will be recovered&lt;br /&gt;
** in case of a power outage or kernel crash, data might be lost&lt;br /&gt;
* allows buffering of the log file in return for the risk of data loss&lt;br /&gt;
* use it for data where you need a high update performance but cannot afford losing the last few seconds of your work&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = safe ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory&lt;br /&gt;
* the main storage is mirrored on disk&lt;br /&gt;
* changes to the delta storage are logged on disk files&lt;br /&gt;
* an operation only succeeds after the data is synced to disk permanently&lt;br /&gt;
* in case of a crash, all data will be recovered&lt;br /&gt;
* introduces delays for each transaction since the system has to wait for a write fence&lt;br /&gt;
* IO bound (limited to ~1,700 write operations per second)&lt;br /&gt;
* use it for accounting data or any data that must not be lost&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Persistency_and_Performance_Guarantees&amp;diff=262</id>
		<title>Persistency and Performance Guarantees</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Persistency_and_Performance_Guarantees&amp;diff=262"/>
		<updated>2026-03-09T12:16:10Z</updated>

		<summary type="html">&lt;p&gt;Carli: /* Persistency Guarantees */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;MemCP gives the user several Guarantees for persistency and performance. These are the guarantees:&lt;br /&gt;
&lt;br /&gt;
== Performance Guarantees ==&lt;br /&gt;
MemCP guarantees that:&lt;br /&gt;
&lt;br /&gt;
* Insert/Update without any unique key check or foreign key check will scale over shards&lt;br /&gt;
* Aggregate functions like SUM, AVG will scale perfectly with the amount of CPUs&lt;br /&gt;
&lt;br /&gt;
With these guarantees, you can add more CPU cores whenever you have more data to ensure the same query time even with growing data.&lt;br /&gt;
&lt;br /&gt;
Please consider that memory bandwith still might be a bottleneck. Even modern 128 core CPUs do not scale better than 8 cores for uncompressed data (usually 40 GiB/s bandwith on tested machines). &#039;&#039;&#039;MemCPs [[Columnar Storage]] scales beyond that limit.&#039;&#039;&#039;&lt;br /&gt;
== Persistency Guarantees ==&lt;br /&gt;
There are five persistency modes per table which are:&lt;br /&gt;
&lt;br /&gt;
* ENGINE = cache&lt;br /&gt;
* ENGINE = memory&lt;br /&gt;
* ENGINE = sloppy&lt;br /&gt;
* ENGINE = logged&lt;br /&gt;
* ENGINE = safe&lt;br /&gt;
In comparison to other RDBMs, MemCP can do this setting per table. MySQL/MariaDB for instance only allows a global setting which is sometimes not what you want.&lt;br /&gt;
&lt;br /&gt;
In short, these engines guarantee different performance:&lt;br /&gt;
&lt;br /&gt;
* cache+memory -&amp;gt; RAM speed, no persistency&lt;br /&gt;
* sloppy+logged -&amp;gt; HDD speed, persistency guarantees under circumstances&lt;br /&gt;
* safe -&amp;gt; Sync speed (slow) and persistency guarantees even in case of power outage during queries&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = cache ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory and only in memory&lt;br /&gt;
* in case of a crash, all data is gone&lt;br /&gt;
* in case the server is running out of RAM, the data can be deleted, too&lt;br /&gt;
* the schema is saved on disk&lt;br /&gt;
* after a recovery, the table starts empty&lt;br /&gt;
* fastest way to store data&lt;br /&gt;
* use it for session data, observer handles, caches and other data that can be recreated by the software&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = memory ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory and only in memory&lt;br /&gt;
* in case of a crash, all data is gone&lt;br /&gt;
* while the server is running, the data will be kept alive&lt;br /&gt;
* the schema is saved on disk&lt;br /&gt;
* after a recovery, the table starts empty&lt;br /&gt;
* fastest way to store data&lt;br /&gt;
* use it for session data, observer handles, caches and other data that can be recreated by the software&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = sloppy ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory&lt;br /&gt;
* the main storage is mirrored on disk&lt;br /&gt;
* the delta storage is RAM-only&lt;br /&gt;
* a main storage rebuild is triggered every 15 minutes, so data older than 15 minutes are guaranteed to be persistent&lt;br /&gt;
* in case of a crash, the delta storage is gone, the main storage is recovered&lt;br /&gt;
* after a recovery, some datasets or deletions that happend in the last 15 minutes before the crash may be gone&lt;br /&gt;
* extremely fast way to store data without the fear of losing them in normal operation&lt;br /&gt;
* use it for frequently updated tables with unimportant data like usage statistics or sensor data&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = logged ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory&lt;br /&gt;
* the main storage is mirrored on disk&lt;br /&gt;
* changes to the delta storage are logged on disk files&lt;br /&gt;
* an operation succeeds even if data is not synced to disk permanently yet&lt;br /&gt;
* in case of a crash, data might be recovered&lt;br /&gt;
** in case of a crash of the process, all data will be recovered&lt;br /&gt;
** in case of a power outage or kernel crash, data might be lost&lt;br /&gt;
* allows buffering of the log file in return for the risk of data loss&lt;br /&gt;
* use it for data where you need a high update performance but cannot afford losing the last few seconds of your work&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = safe ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory&lt;br /&gt;
* the main storage is mirrored on disk&lt;br /&gt;
* changes to the delta storage are logged on disk files&lt;br /&gt;
* an operation only succeeds after the data is synced to disk permanently&lt;br /&gt;
* in case of a crash, all data will be recovered&lt;br /&gt;
* introduces delays for each transaction since the system has to wait for a write fence&lt;br /&gt;
* IO bound (limited to ~1,700 write operations per second)&lt;br /&gt;
* use it for accounting data or any data that must not be lost&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
	<entry>
		<id>https://www.memcp.org/index.php?title=Persistency_and_Performance_Guarantees&amp;diff=261</id>
		<title>Persistency and Performance Guarantees</title>
		<link rel="alternate" type="text/html" href="https://www.memcp.org/index.php?title=Persistency_and_Performance_Guarantees&amp;diff=261"/>
		<updated>2026-03-09T12:13:49Z</updated>

		<summary type="html">&lt;p&gt;Carli: /* Persistency Guarantees */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;MemCP gives the user several Guarantees for persistency and performance. These are the guarantees:&lt;br /&gt;
&lt;br /&gt;
== Performance Guarantees ==&lt;br /&gt;
MemCP guarantees that:&lt;br /&gt;
&lt;br /&gt;
* Insert/Update without any unique key check or foreign key check will scale over shards&lt;br /&gt;
* Aggregate functions like SUM, AVG will scale perfectly with the amount of CPUs&lt;br /&gt;
&lt;br /&gt;
With these guarantees, you can add more CPU cores whenever you have more data to ensure the same query time even with growing data.&lt;br /&gt;
&lt;br /&gt;
Please consider that memory bandwith still might be a bottleneck. Even modern 128 core CPUs do not scale better than 8 cores for uncompressed data (usually 40 GiB/s bandwith on tested machines). &#039;&#039;&#039;MemCPs [[Columnar Storage]] scales beyond that limit.&#039;&#039;&#039;&lt;br /&gt;
== Persistency Guarantees ==&lt;br /&gt;
There are five persistency modes per table which are:&lt;br /&gt;
&lt;br /&gt;
* ENGINE = cache&lt;br /&gt;
* ENGINE = memory&lt;br /&gt;
* ENGINE = sloppy&lt;br /&gt;
* ENGINE = logged&lt;br /&gt;
* ENGINE = safe&lt;br /&gt;
In comparison to other RDBMs, MemCP can do this setting per table. MySQL/MariaDB for instance only allows a global setting which is sometimes not what you want.&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = cache ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory and only in memory&lt;br /&gt;
* in case of a crash, all data is gone&lt;br /&gt;
* in case the server is running out of RAM, the data can be deleted, too&lt;br /&gt;
* the schema is saved on disk&lt;br /&gt;
* after a recovery, the table starts empty&lt;br /&gt;
* fastest way to store data&lt;br /&gt;
* use it for session data, observer handles, caches and other data that can be recreated by the software&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = memory ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory and only in memory&lt;br /&gt;
* in case of a crash, all data is gone&lt;br /&gt;
* while the server is running, the data will be kept alive&lt;br /&gt;
* the schema is saved on disk&lt;br /&gt;
* after a recovery, the table starts empty&lt;br /&gt;
* fastest way to store data&lt;br /&gt;
* use it for session data, observer handles, caches and other data that can be recreated by the software&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = sloppy ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory&lt;br /&gt;
* the main storage is mirrored on disk&lt;br /&gt;
* the delta storage is RAM-only&lt;br /&gt;
* a main storage rebuild is triggered every 15 minutes, so data older than 15 minutes are guaranteed to be persistent&lt;br /&gt;
* in case of a crash, the delta storage is gone, the main storage is recovered&lt;br /&gt;
* after a recovery, some datasets or deletions that happend in the last 15 minutes before the crash may be gone&lt;br /&gt;
* extremely fast way to store data without the fear of losing them in normal operation&lt;br /&gt;
* use it for frequently updated tables with unimportant data like usage statistics or sensor data&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = logged ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory&lt;br /&gt;
* the main storage is mirrored on disk&lt;br /&gt;
* changes to the delta storage are logged on disk files&lt;br /&gt;
* an operation succeeds even if data is not synced to disk permanently yet&lt;br /&gt;
* in case of a crash, data might be recovered&lt;br /&gt;
** in case of a crash of the process, all data will be recovered&lt;br /&gt;
** in case of a power outage or kernel crash, data might be lost&lt;br /&gt;
* allows buffering of the log file in return for the risk of data loss&lt;br /&gt;
* use it for data where you need a high update performance but cannot afford losing the last few seconds of your work&lt;br /&gt;
&lt;br /&gt;
=== ENGINE = safe ===&lt;br /&gt;
&lt;br /&gt;
* all data is held in memory&lt;br /&gt;
* the main storage is mirrored on disk&lt;br /&gt;
* changes to the delta storage are logged on disk files&lt;br /&gt;
* an operation only succeeds after the data is synced to disk permanently&lt;br /&gt;
* in case of a crash, all data will be recovered&lt;br /&gt;
* introduces delays for each transaction since the system has to wait for a write fence&lt;br /&gt;
* IO bound (limited to ~1,700 write operations per second)&lt;br /&gt;
* use it for accounting data or any data that must not be lost&lt;/div&gt;</summary>
		<author><name>Carli</name></author>
	</entry>
</feed>