Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 93221b2905 | |||
| 839572f1fb | |||
| 266b5a6985 | |||
| 3b9fbf42a0 | |||
| ec4b4a4ece | |||
| 6dbf2f9675 | |||
| d349aad2e6 | |||
| d25580239e | |||
| 5c7fbcbbfc | |||
| d7b093812d | |||
| 284e75ddb3 | |||
| c1fd53845f | |||
| 2b57349519 | |||
| 45c97653ca |
+1
-1
@@ -84,7 +84,7 @@ ssh <docker-host> "docker exec -u www-data nextcloud-aio-nextcloud php occ app:d
|
||||
## `max-version` policy
|
||||
|
||||
See the comment next to `<dependencies>` in `appinfo/info.xml`: it must always equal the
|
||||
highest Nextcloud core version this fork has actually been verified against — never a
|
||||
highest Nextcloud core version this app has actually been verified against — never a
|
||||
value inherited from upstream, and never a guess ahead of what's been tested. Test
|
||||
against the next major's beta ahead of time and bump it before that major goes final,
|
||||
rather than reacting after the fact.
|
||||
|
||||
@@ -1,22 +1,26 @@
|
||||
# OCCWeb terminal (maintained fork)
|
||||
# Extended OCC Web (occ & SQL terminal)
|
||||
|
||||
### A web terminal for admins to launch Nextcloud's occ commands
|
||||
### A web terminal for Nextcloud admins to run occ commands and SQL queries
|
||||
|
||||
Available in the [Nextcloud App Store](https://apps.nextcloud.com/apps/extended_occweb) as `extended_occweb`.
|
||||
|
||||

|
||||
|
||||
## About this fork
|
||||
## History
|
||||
|
||||
The original [Adphi/occweb](https://github.com/Adphi/occweb) was marked deprecated by its
|
||||
author and is unmaintained. This fork tracks [fanategorius/occweb](https://github.com/fanategorius/occweb),
|
||||
which picked up compatibility maintenance where Adphi left off, and adds SQL query mode,
|
||||
author and is unmaintained. This project started as a fork of
|
||||
[fanategorius/occweb](https://github.com/fanategorius/occweb), which had picked up
|
||||
compatibility maintenance where Adphi left off, and tracked it while adding SQL query mode,
|
||||
security hardening (admin checks, CSRF/confirmation flows, transactional batches), and PHP
|
||||
8.1+ compatibility fixes on top.
|
||||
8.1+ compatibility fixes. Since 0.4.3 it is published under its own app id,
|
||||
`extended_occweb`, and it is now maintained as an independent project.
|
||||
|
||||
### Credits
|
||||
|
||||
- [Adphi/occweb](https://github.com/Adphi/occweb) — original author/project.
|
||||
- [fanategorius/occweb](https://github.com/fanategorius/occweb) — the actively maintained
|
||||
fork this repo is based on and tracks.
|
||||
- [fanategorius/occweb](https://github.com/fanategorius/occweb) — the maintained fork this
|
||||
project was based on.
|
||||
- [Git-Usr123/occweb](https://github.com/Git-Usr123/occweb) — independent fork; the
|
||||
`OC::$server->getConfig()` → `OC::$server->get(\OCP\IConfig::class)` fix in
|
||||
`OccController.php` was spotted there and backported here.
|
||||
@@ -85,6 +89,10 @@ run the whole block in a single request — this matters for scripts like
|
||||
statement in one submission runs on the same database connection/session.
|
||||
Type `occ` to switch back to the normal occ-command mode.
|
||||
|
||||
Long values in result tables are cut to fit the terminal. Add `--full` to the
|
||||
query (it is an SQL comment, so the database ignores it) to see them in full,
|
||||
e.g. `SELECT configvalue FROM oc_appconfig WHERE configkey = 'x'; --full`.
|
||||
|
||||
Every statement that changes data or the schema (`DELETE`, `UPDATE`,
|
||||
`INSERT`, `DROP`, a data-modifying `WITH`, ...) asks for confirmation before
|
||||
the batch runs. There is still no undo — double check what you are about to
|
||||
@@ -170,19 +178,15 @@ was verified, so a rollback target is obvious if a newer major causes problems.
|
||||
|
||||
| occweb version | Tag | NC version tested | Result |
|
||||
|---|---|---|---|
|
||||
| 0.3.4 | `v0.3.4` | 33.0.8 | ✅ Verified (nc01, 2026-09-25) |
|
||||
| 0.3.4 | `v0.3.4` | 34.0.4 | ❌ Blank terminal - global jQuery gone on NC34 (`jQuery is not defined`), then a 412 "CSRF check failed" on every ajax call once jQuery was vendored. Fixed in 0.3.5. |
|
||||
| 0.3.5 | `v0.3.5-nc34` | 34.0.4 | ✅ Verified (nc01, 2026-09-26) - vendors its own jQuery + sends the CSRF `requesttoken` header explicitly on every ajax call |
|
||||
| 0.3.5 | `v0.3.5-nc34` | 33.0.8 | ⚠️ Believed compatible (the 0.3.5 change is additive-only, nothing removed that NC30-33 depended on) but not re-verified - nc01 no longer runs NC33 to test against |
|
||||
| 0.4.0 | (untagged) | 34.0.4 | ✅ Verified (nc01, 2026-09-26) - app id renamed `occweb` → `extended_occweb` (App Store prep), no functional changes to the 0.3.5 fixes otherwise |
|
||||
| 0.4.1 | `v0.4.1-nc34` | 34.0.4 | ✅ Verified (nc01, 2026-09-26) - code review fixes: correct jQuery `.fail()` signature, added a missing `.fail()` handler on the initial terminal-load request |
|
||||
| 0.4.1 | `v0.4.1-nc34` | 33.0.8 | ⚠️ Same caveat as 0.3.5/0.4.0 - not re-verified, no NC33 test environment available. Also unresolved: `js/jquery.js` now loads unconditionally on every supported version, even NC30-33 where core still provides jQuery - flagged in code review, needs an NC33 environment to confirm it's harmless there. |
|
||||
| 0.4.2 | (untagged) | 32.0.15 | ✅ Verified (`testbak/`, 2026-09-27) - terminal loads and runs commands correctly. Confirms the suspected jQuery issue above: core still exposes a read-only `window.$` getter here, so our vendored `js/jquery.js` throws `TypeError: Cannot set property $ of #<Window> which has only a getter` on load - a real, uncaught console exception, but harmless in practice since the app attaches via `window.jQuery` (still writable), not `window.$`. Fixed in 0.4.3. |
|
||||
| 0.4.2 | (untagged) | 33.0.9 | ✅ Verified (`testbak/`, 2026-09-27) - same result as 32.0.15: functional, same harmless-but-real `window.$` console exception. Fixed in 0.4.3. |
|
||||
| 0.4.2 | (untagged) | 35.0.1 | ✅ Verified (`testbak/`, 2026-09-27) after a real fix: the bootstrap request 500'd with a PHP fatal, `Declaration of OccOutput::setErrorOutput() must be compatible with ConsoleOutputInterface::setErrorOutput(): void` - NC35 bundles a Symfony Console version whose interface now declares that return type. Fixed by adding `: void` to `OccOutput::setErrorOutput()` (`lib/Controller/OccOutput.php`), which is compatible with every earlier Symfony/NC version too. Confirmed clean afterwards: no console errors, no CSRF issues, terminal fully functional. |
|
||||
| 0.4.3 | (untagged) | 32.0.15, 34.0.4 | ✅ Verified (`testbak/`, 2026-09-27) - `templates/index.php` now only loads `js/jquery.js` when `\OCP\ServerVersion::getMajorVersion() >= 34`, since core still provides a working jQuery on 32/33. Re-tested both sides of the boundary: NC32 loads no `jquery.js` request at all and has zero console errors; NC34 still loads it and still works, confirming no regression. |
|
||||
| 0.3.4 | `v0.3.4` | 33.0.8 | ✅ Verified (2026-09-25). Last release under the old `occweb` id; does not work on NC34 (missing jQuery, CSRF), fixed from 0.3.5 on. |
|
||||
| 0.4.3 | `v0.4.3` | 32.0.15, 33.0.9, 34.0.4, 35.0.1 | ✅ Verified (`testbak/`, 2026-09-27). First release under `extended_occweb`: NC35 fatal in `OccOutput` fixed, vendored jQuery only loaded on NC34+. |
|
||||
| 0.4.4 | (untagged) | 34.0.4 | ✅ Verified (2026-09-30). Brackets in occ output escaped before rendering. |
|
||||
| 0.4.5 | `v0.4.5` | 32.0.15, 33.0.9, 34.0.4, 35.0.1 | ✅ Verified (`testbak/`, 2026-09-30). SQL mode hardening, occ output sanitized, first release code-signed with the Nextcloud certificate. |
|
||||
| 0.4.6 | `v0.4.6` | 32.0.15, 33.0.9, 34.0.4, 35.0.1 | ✅ Verified (`testbak/`, 2026-09-30). occ commands logged for the audit trail, console built from the container, more SQL guard gaps closed, long values in result tables cut to fit (`--full` shows them). |
|
||||
|
||||
`min-version`/`max-version` in `appinfo/info.xml` were updated from `30`/`34` to `32`/`35` on 2026-09-27 based on the above: 30/31 have never actually been tested (not even before the app-id rename) so claiming them was never justified once the `testbak/`-based verification policy existed, and 35 is now a genuinely verified (and fixed) target rather than a guess. 30/31 are also past Nextcloud's own currently-supported boundary as of 2026-09-18 (32-35 supported), which independently confirms 32 as the right floor.
|
||||
Older entries (0.3.5-0.4.2) are in the git history of this file.
|
||||
|
||||
`min-version`/`max-version` in `appinfo/info.xml` are `32`/`35` since 2026-09-27: 30/31 were never tested and are past Nextcloud's supported range, and 35 is verified rather than guessed.
|
||||
|
||||
If a future major breaks something, `v0.3.4` is the last version confirmed working on NC33
|
||||
and older - but a plain `git checkout v0.3.4` is **not** a working rollback by itself. That
|
||||
|
||||
+28
-4
@@ -3,9 +3,30 @@
|
||||
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
|
||||
<id>extended_occweb</id>
|
||||
<name>Extended OCC Web</name>
|
||||
<summary>OCC Commands in a web terminal</summary>
|
||||
<description><![CDATA[Run OCC Commands in a web terminal]]></description>
|
||||
<version>0.4.5</version>
|
||||
<summary>Run occ commands and SQL queries from a web terminal (admins only)</summary>
|
||||
<description><![CDATA[A terminal in the browser for Nextcloud administrators: run occ commands and query the database without shell access to the server. Handy on Nextcloud All-in-One (AIO) and other container setups, where occ otherwise needs `docker exec`.
|
||||
|
||||
**occ mode**
|
||||
|
||||
- Run any occ command, with tab completion of command names and colored output.
|
||||
- Every command is logged with the user who ran it, in the Nextcloud log and, when enabled, in the admin_audit log.
|
||||
|
||||
**SQL mode** (type `sql`)
|
||||
|
||||
- Run SQL against the Nextcloud database. Statements separated by `;` run as one batch on one connection, and the batch is rolled back if a statement fails.
|
||||
- Results are shown as tables (up to 1000 rows per query).
|
||||
- Statements that change data or the schema ask for confirmation before the batch runs. Reading or writing files on the database server and starting programs through SQL are blocked.
|
||||
- Ready-made scripts: type `templates`, for example to look up or completely delete a local user. A template only fills the command line; nothing runs until you review it and press Enter.
|
||||
|
||||
**Security**
|
||||
|
||||
- Only members of the Nextcloud admin group can use the app; every request is checked and CSRF-protected.
|
||||
- Treat access to it like shell access to the server, and run the database as a user without superuser or server file/program rights. See the Security section in the README.
|
||||
|
||||
**Limitations**
|
||||
|
||||
- Not an interactive terminal: long-running commands (like `files:scan` on a large instance) time out, and commands that ask questions cannot be answered (use `-n`).]]></description>
|
||||
<version>0.4.6</version>
|
||||
<licence>agpl</licence>
|
||||
<author mail="dillard.blom@ensembia.com" >Dillard Blom</author>
|
||||
<namespace>OCCWeb</namespace>
|
||||
@@ -14,9 +35,12 @@
|
||||
<bugs>https://github.com/dillardblom/occweb/issues</bugs>
|
||||
<repository>https://github.com/dillardblom/occweb</repository>
|
||||
<screenshot>https://github.com/dillardblom/occweb/raw/main/appinfo/screenshot.png</screenshot>
|
||||
<screenshot>https://github.com/dillardblom/occweb/raw/main/appinfo/screenshot-status.png</screenshot>
|
||||
<screenshot>https://github.com/dillardblom/occweb/raw/main/appinfo/screenshot-sql-switch.png</screenshot>
|
||||
<screenshot>https://github.com/dillardblom/occweb/raw/main/appinfo/screenshot-sql.png</screenshot>
|
||||
<dependencies>
|
||||
<!-- min-version and max-version must equal the lowest/highest NC core
|
||||
versions this fork has actually been verified on (via testbak/,
|
||||
versions this app has actually been verified on (via testbak/,
|
||||
see its README) - never inherited from upstream or guessed at
|
||||
either end. min-version was 30 pre-testbak, unverified since the
|
||||
app-id rename/jQuery fixes - narrowed to 32 (2026-09-27) once 30/31
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 95 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 614 KiB After Width: | Height: | Size: 101 KiB |
+38
-6
@@ -203,7 +203,10 @@
|
||||
}
|
||||
|
||||
// Tabular rendering of SELECT results, psql-style.
|
||||
function renderTable(term, rows) {
|
||||
// Unless full is set, the widest columns are narrowed until the table
|
||||
// fits the terminal, so one long value doesn't wrap the whole table.
|
||||
// Returns true when a value was cut.
|
||||
function renderTable(term, rows, full) {
|
||||
if (!rows || !rows.length) {
|
||||
return;
|
||||
}
|
||||
@@ -234,9 +237,34 @@
|
||||
}, col.length);
|
||||
});
|
||||
|
||||
var MIN_WIDTH = 10;
|
||||
var cut = false;
|
||||
if (!full) {
|
||||
var available = term.cols() - 1;
|
||||
var total = function () {
|
||||
return widths.reduce(function (sum, w) { return sum + w + 3; }, -1);
|
||||
};
|
||||
while (total() > available) {
|
||||
var widest = widths.indexOf(Math.max.apply(null, widths));
|
||||
if (widths[widest] <= MIN_WIDTH) {
|
||||
break;
|
||||
}
|
||||
widths[widest] = Math.max(MIN_WIDTH, widths[widest] - (total() - available));
|
||||
}
|
||||
}
|
||||
|
||||
function fit(str, width) {
|
||||
str = String(str);
|
||||
if (str.length <= width) {
|
||||
return str;
|
||||
}
|
||||
cut = true;
|
||||
return str.slice(0, width - 1) + '\u2026';
|
||||
}
|
||||
|
||||
function formatRow(cells) {
|
||||
return cells.map(function (cell, i) {
|
||||
return ' ' + pad(cell, widths[i]) + ' ';
|
||||
return ' ' + pad(fit(cell, widths[i]), widths[i]) + ' ';
|
||||
}).join('|');
|
||||
}
|
||||
|
||||
@@ -248,9 +276,10 @@
|
||||
});
|
||||
|
||||
term.echo($.terminal.escape_formatting(lines.join('\n')));
|
||||
return cut;
|
||||
}
|
||||
|
||||
function renderSqlResponse(term, response) {
|
||||
function renderSqlResponse(term, response, full) {
|
||||
if (!response) {
|
||||
term.echo('[[;#ff5555;]Empty response from server]');
|
||||
return;
|
||||
@@ -270,8 +299,8 @@
|
||||
term.echo('[[;#ff5555;] Error: ]' + $.terminal.escape_formatting(r.error || 'unknown error'));
|
||||
} else if (r.type === 'select') {
|
||||
term.echo('[[;gray;] ' + r.count + ' row(s)]');
|
||||
if (r.count > 0) {
|
||||
renderTable(term, r.data);
|
||||
if (r.count > 0 && renderTable(term, r.data, full)) {
|
||||
term.echo('[[;gray;] Long values are cut to fit the terminal. Add --full to the query to see them in full.]');
|
||||
}
|
||||
if (r.truncated) {
|
||||
term.echo('[[;yellow;] Result truncated — showing only the first ' + r.count + ' rows, add LIMIT to see more precisely.]');
|
||||
@@ -327,7 +356,10 @@
|
||||
askDeleteConfirmation(term, sql, response.error);
|
||||
return;
|
||||
}
|
||||
renderSqlResponse(term, response);
|
||||
// "--full" is a plain SQL comment, so the database ignores it; string
|
||||
// literals are left out so a value containing it doesn't count
|
||||
var withoutStrings = sql.replace(/'(?:[^']|'')*'/g, "''").replace(/"(?:[^"]|"")*"/g, '""');
|
||||
renderSqlResponse(term, response, /(^|\s)-- ?full\b/.test(withoutStrings));
|
||||
term.resume();
|
||||
}).fail(function (xhr, status) {
|
||||
if (status === 'timeout') {
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace OCA\OCCWeb\Controller;
|
||||
use Exception;
|
||||
use OC;
|
||||
use OC\Console\Application;
|
||||
use OC\MemoryInfo;
|
||||
use OCP\IRequest;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\AppFramework\Http\DataResponse;
|
||||
@@ -21,6 +20,7 @@ class OccController extends Controller
|
||||
private $userId;
|
||||
|
||||
private $application;
|
||||
private $fakeRequest;
|
||||
private $symphonyApplication;
|
||||
private $output;
|
||||
|
||||
@@ -30,16 +30,8 @@ class OccController extends Controller
|
||||
$this->logger = OC::$server->get(LoggerInterface::class);
|
||||
$this->userId = $userId;
|
||||
|
||||
$this->application = new Application(
|
||||
OC::$server->get(\OCP\ServerVersion::class),
|
||||
OC::$server->get(\OCP\IConfig::class),
|
||||
OC::$server->get(\OCP\EventDispatcher\IEventDispatcher::class),
|
||||
new FakeRequest(),
|
||||
$this->logger,
|
||||
OC::$server->query(MemoryInfo::class),
|
||||
OC::$server->get(\OCP\App\IAppManager::class), // Obtain the IAppManager
|
||||
OC::$server->get(\OCP\Defaults::class)
|
||||
);
|
||||
$this->fakeRequest = new FakeRequest();
|
||||
$this->application = $this->createConsoleApplication($this->fakeRequest);
|
||||
$this->application->setAutoExit(false);
|
||||
$this->output = new OccOutput(OutputInterface::VERBOSITY_NORMAL, true);
|
||||
$this->application->loadCommands(new StringInput(""), $this->output);
|
||||
@@ -82,6 +74,24 @@ class OccController extends Controller
|
||||
return new TemplateResponse('extended_occweb', 'index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds Nextcloud's console application with its dependencies from the
|
||||
* container, except the request: the console reads argv from it for the
|
||||
* ConsoleEvent (used by admin_audit), which a web request doesn't have.
|
||||
* Resolving the arguments by type keeps this working when Nextcloud
|
||||
* changes the constructor, which it has done several times.
|
||||
*/
|
||||
private function createConsoleApplication(IRequest $request): Application
|
||||
{
|
||||
$arguments = [];
|
||||
foreach ((new \ReflectionClass(Application::class))->getConstructor()->getParameters() as $parameter) {
|
||||
$type = $parameter->getType();
|
||||
$class = $type instanceof \ReflectionNamedType ? $type->getName() : null;
|
||||
$arguments[] = $class === IRequest::class ? $request : OC::$server->get($class);
|
||||
}
|
||||
return new Application(...$arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $input
|
||||
* @return string
|
||||
@@ -104,7 +114,15 @@ class OccController extends Controller
|
||||
public function cmd($command)
|
||||
{
|
||||
if ($err = $this->requireAdmin()) return $err;
|
||||
$this->logger->debug($command);
|
||||
// The regular log gets only the command name: arguments can hold
|
||||
// secrets (config:system:set --value=...). The full command goes to
|
||||
// admin_audit through the ConsoleEvent, like occ on the CLI.
|
||||
$this->logger->warning('[extended_occweb] occ command by {user}: {command}', [
|
||||
'app' => 'extended_occweb',
|
||||
'user' => $this->userId,
|
||||
'command' => strtok(trim((string) $command), " \t\n") ?: '(empty)',
|
||||
]);
|
||||
$this->fakeRequest->server['argv'] = ['occ', $command];
|
||||
$input = new StringInput($command);
|
||||
$response = $this->run($input);
|
||||
$this->logger->debug($response);
|
||||
|
||||
@@ -27,7 +27,7 @@ class SqlGuard
|
||||
'/\bpg_stat_file\s*\(/i' => 'pg_stat_file()',
|
||||
'/\blo_import\s*\(/i' => 'lo_import()',
|
||||
'/\blo_export\s*\(/i' => 'lo_export()',
|
||||
'/\bdblink(_connect)?\s*\(/i' => 'dblink() (connects to arbitrary databases)',
|
||||
'/\bdblink\w*\s*\(/i' => 'dblink functions (connect to arbitrary databases)',
|
||||
'/\bLOAD_FILE\s*\(/i' => 'LOAD_FILE()',
|
||||
'/\bINTO\s+(OUTFILE|DUMPFILE)\b/i' => 'INTO OUTFILE/DUMPFILE',
|
||||
];
|
||||
@@ -87,8 +87,9 @@ class SqlGuard
|
||||
|
||||
$statements[] = trim($current);
|
||||
|
||||
// A trailing comment ("SELECT 1; -- note") is not a statement
|
||||
return array_values(array_filter($statements, function ($s) {
|
||||
return $s !== '';
|
||||
return trim(self::removeComments($s)) !== '';
|
||||
}));
|
||||
}
|
||||
|
||||
@@ -122,7 +123,14 @@ class SqlGuard
|
||||
while ($i < $len) {
|
||||
$end = self::literalEnd($sql, $i);
|
||||
if ($end !== null) {
|
||||
$result .= $replaceLiterals ? ($sql[$i] === '"' ? '""' : "''") : substr($sql, $i, $end - $i);
|
||||
$literal = substr($sql, $i, $end - $i);
|
||||
if (preg_match('/^"([A-Za-z_][A-Za-z0-9_$]*)"$/', $literal, $m) && preg_match('/\G(?:\s|--[^\n]*(?:\n|$)|\/\*[\s\S]*?\*\/)*\(/', $sql, $unused, 0, $end)) {
|
||||
// A quoted function name ("setval"(...)) calls the same
|
||||
// function as the bare word, so check it as one
|
||||
$result .= $m[1];
|
||||
} else {
|
||||
$result .= $replaceLiterals ? ($sql[$i] === '"' ? '""' : "''") : $literal;
|
||||
}
|
||||
$i = $end;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,13 @@ class SqlGuardTest extends TestCase
|
||||
["SELECT pg_ls_dir('/')"],
|
||||
["SELECT lo_import('/etc/passwd')"],
|
||||
["SELECT dblink_connect('host=x')"],
|
||||
["SELECT dblink_exec('host=x', 'DROP TABLE t')"],
|
||||
["SELECT \"pg_read_file\"('/etc/passwd')"],
|
||||
["SELECT pg_catalog.\"pg_read_file\"('/etc/passwd')"],
|
||||
["SELECT \"pg_read_file\" /* x */ ('/etc/passwd')"],
|
||||
["SELECT \"pg_read_file\"-- x\n('/etc/passwd')"],
|
||||
["SELECT dblink_send_query('c', 'SELECT 1')"],
|
||||
["SELECT * FROM dblink('host=x', 'SELECT 1') AS t(a int)"],
|
||||
["SELECT * FROM t INTO OUTFILE '/tmp/x'"],
|
||||
["COPY (SELECT '/*') TO PROGRAM 'sh' --*/"],
|
||||
["COPY (SELECT '--') TO PROGRAM 'sh'"],
|
||||
@@ -119,6 +126,10 @@ class SqlGuardTest extends TestCase
|
||||
["SELECT set_config('x', 'y', false)"],
|
||||
["SELECT setval('seq', 1)"],
|
||||
["SELECT nextval('seq')"],
|
||||
["SELECT \"setval\"('seq', 1)"],
|
||||
["SELECT pg_catalog.\"setval\"('seq', 1)"],
|
||||
["SELECT pg_catalog.setval('seq', 1)"],
|
||||
["SELECT \"setval\" /* x */ ('seq', 1)"],
|
||||
['MERGE INTO t USING s ON true WHEN MATCHED THEN DELETE'],
|
||||
['VACUUM'],
|
||||
['PRAGMA journal_mode = WAL'],
|
||||
@@ -159,6 +170,10 @@ class SqlGuardTest extends TestCase
|
||||
["/* it's; here */ SELECT 1; SELECT 2", ["/* it's; here */ SELECT 1", 'SELECT 2']],
|
||||
['SELECT \$1; SELECT 2', ['SELECT \$1', 'SELECT 2']],
|
||||
[' ; ;SELECT 1;', ['SELECT 1']],
|
||||
["SELECT 1; --full", ['SELECT 1']],
|
||||
["SELECT 1; -- note\nSELECT 2", ['SELECT 1', "-- note\nSELECT 2"]],
|
||||
["-- only a comment", []],
|
||||
["SELECT 1; /* note */", ['SELECT 1']],
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user