Repository: duckdb/duckdb
File: tools/shell/shell.cpp (C++)

Code before:
			if (!db) {
				OpenDB();
			}
			const char *query = args[++iName].c_str();

			auto statement = conn->Prepare(query);
			if (statement->HasError()) {
				PrintDatabaseError(statement->GetError());
				return false;
			}

			auto res = statement->Execute();
			if (res->HasError()) {
				PrintDatabaseError(res->GetError());
				return false;
			}

			if (res->ColumnCount() != 1) {
				utf8_printf(stderr, "Error: --sql query must produce exactly one value, one row with one column\n");
				return false;
			}

			auto result_chunk = res->Fetch();
			auto &properties = res->properties;

			if (!result_chunk || result_chunk->size() == 0 ||
			    properties.return_type != duckdb::StatementReturnType::QUERY_RESULT) {
				utf8_printf(stderr, "Error: --sql query did not produce a row\n");
				return false;
			}

			if (result_chunk->size() > 1) {
				utf8_printf(stderr, "Error: --sql query produced multiple rows\n");
				return false;
			}

			auto val = result_chunk->GetValue(0, 0);
			if (val.IsNull()) {
				utf8_printf(stderr, "Error: --sql query produced a NULL value\n");
				return false;
			}

			zNewFilename = val.ToString();
			has_sql = true;
		} else if (z[0] == '-') {
			utf8_printf(stderr, "unknown option: %s\n", z);
			return false;
		}
	}

	if (has_sql && args.size() > iName) {

Review comment (suggestion):
This seems pretty round-about, I made a shorter version as part of my [dynamic prompt PR](https://github.com/duckdb/duckdb/pull/19579):

```cpp
string Prompt::EvaluateSQL(ShellState &state, const string &sql) {
	state.OpenDB();
	auto &con = *state.conn;
	auto result = con.Query(sql);
	if (result->HasError()) {
		return "#ERROR#:" + result->GetError();
	}
	auto &collection = result->Collection();
	if (collection.Count() > 1) {
		return "#TOO MANY ROWS#";
	}
	if (collection.ColumnCount() != 1) {
		return "#TOO MANY COLUMNS#";
	}
	for (auto &row : collection.Rows()) {
		return row.GetValue(0).ToString();
	}
	return "#EMPTY#";
}
```

Since these are effectively doing the same thing it would be great if we could unify these into a single function in `ShellState` that is called by both places.

Code after:
			// move forward and find the next dollar
			zSql++;
			auto start = zSql;
			while (*zSql && *zSql != '$') {
				zSql++;
			}
			if (!zSql[0]) {
				// reached end of string while looking for the dollar
				return nullptr;
			}
			// check if the dollar quoted string name matches
			if (delimiterLength == idx_t(zSql - start)) {
				if (memcmp(start, delimiterStart, delimiterLength) == 0) {
					return zSql;
				}
			}
			// dollar does not match - reset position to start and keep looking
			zSql = start - 1;
		}
	}
	// unterminated
	return nullptr;
}

bool ShellState::SQLIsComplete(const char *zSql) {
	auto state = SQLParseState::NORMAL;

	for (; *zSql; zSql++) {
		SQLParseState next_state;
		switch (*zSql) {
		case ';':
			next_state = SQLParseState::SEMICOLON;
			break;
		case ' ':
		case '\r':
		case '\t':
		case '\n':
		case '\f': { /* White space is ignored */
			next_state = SQLParseState::WHITESPACE;
			break;
		}
		case '/': { /* C-style comments */
			if (zSql[1] != '*') {
				next_state = SQLParseState::NORMAL;
				break;
			}
			zSql += 2;
			while (zSql[0] && (zSql[0] != '*' || zSql[1] != '/')) {
				zSql++;
			}
			if (zSql[0] == 0) {