|
@@ -81,6 +81,7 @@ public int main(string[] args) {
|
|
|
print("\n--- Error Path Tests ---\n");
|
|
print("\n--- Error Path Tests ---\n");
|
|
|
test_syntax_error(conn);
|
|
test_syntax_error(conn);
|
|
|
test_unique_violation(conn);
|
|
test_unique_violation(conn);
|
|
|
|
|
+ test_placeholder_edge_cases(conn);
|
|
|
test_missing_parameter(conn);
|
|
test_missing_parameter(conn);
|
|
|
|
|
|
|
|
print("\n--- Mixed Integration Tests ---\n");
|
|
print("\n--- Mixed Integration Tests ---\n");
|
|
@@ -956,6 +957,64 @@ void test_unique_violation(Connection conn) throws SqlError {
|
|
|
pass("unique violation");
|
|
pass("unique violation");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void test_placeholder_edge_cases(Connection conn) throws SqlError {
|
|
|
|
|
+ print("Test: placeholder translation edge cases... ");
|
|
|
|
|
+ string? s = null;
|
|
|
|
|
+ int64? v = null;
|
|
|
|
|
+
|
|
|
|
|
+ // Array slice: the colon between digits inside brackets is not a placeholder.
|
|
|
|
|
+ var rows = conn.create_command(
|
|
|
|
|
+ "SELECT (ARRAY[1,2,3])[1:2]::text AS arr, :w AS w"
|
|
|
|
|
+ ).with_parameter("w", 9).execute_query().to_array();
|
|
|
|
|
+ assert(rows.length == 1);
|
|
|
|
|
+ assert(rows[0].get("arr").try_get_as<string>(out s) && s == "{1,2}");
|
|
|
|
|
+ assert(rows[0].get("w").try_get_as<int64?>(out v) && v == 9);
|
|
|
|
|
+
|
|
|
|
|
+ // Anonymous dollar-quoted string: ':z' inside must stay literal.
|
|
|
|
|
+ var dq = conn.create_command(
|
|
|
|
|
+ "SELECT $$dq :z$$ AS dq, :w AS w"
|
|
|
|
|
+ ).with_parameter("w", 9).execute_query().to_array();
|
|
|
|
|
+ assert(dq[0].get("dq").try_get_as<string>(out s) && s == "dq :z");
|
|
|
|
|
+
|
|
|
|
|
+ // Tagged dollar-quoted string.
|
|
|
|
|
+ var tagged = conn.create_command(
|
|
|
|
|
+ "SELECT $tag$ has :colon $tag$ AS dq, :w AS w"
|
|
|
|
|
+ ).with_parameter("w", 9).execute_query().to_array();
|
|
|
|
|
+ assert(tagged[0].get("dq").try_get_as<string>(out s) && s == " has :colon ");
|
|
|
|
|
+
|
|
|
|
|
+ // String literal containing a placeholder-looking token.
|
|
|
|
|
+ var lit = conn.create_command(
|
|
|
|
|
+ "SELECT 'lit :y str' AS lit, :w AS w"
|
|
|
|
|
+ ).with_parameter("w", 9).execute_query().to_array();
|
|
|
|
|
+ assert(lit[0].get("lit").try_get_as<string>(out s) && s == "lit :y str");
|
|
|
|
|
+
|
|
|
|
|
+ // Quoted identifier containing a colon comes back as the column name.
|
|
|
|
|
+ var qid = conn.create_command(
|
|
|
|
|
+ "SELECT 7 AS \"we:ird\""
|
|
|
|
|
+ ).execute_query().to_array();
|
|
|
|
|
+ assert(qid[0].get("we:ird").try_get_as<int64?>(out v) && v == 7);
|
|
|
|
|
+
|
|
|
|
|
+ // Duplicate names bind to a single $n; a placeholder at the very end works.
|
|
|
|
|
+ var dup = conn.create_command("SELECT (:w::int + :w::int) AS sum, :w AS tail")
|
|
|
|
|
+ .with_parameter("w", 3).execute_query().to_array();
|
|
|
|
|
+ assert(dup[0].get("sum").try_get_as<int64?>(out v) && v == 6);
|
|
|
|
|
+ assert(dup[0].get("tail").try_get_as<int64?>(out v) && v == 3);
|
|
|
|
|
+
|
|
|
|
|
+ // Line and block comments may contain colons.
|
|
|
|
|
+ var comments = conn.create_command(
|
|
|
|
|
+ "SELECT :w -- comment :ignore\n + 1 AS seven, /* block :nope */ :w AS again"
|
|
|
|
|
+ ).with_parameter("w", 3).execute_query().to_array();
|
|
|
|
|
+ assert(comments[0].get("seven").try_get_as<int64?>(out v) && v == 4);
|
|
|
|
|
+
|
|
|
|
|
+ // A placeholder directly followed by a cast operator.
|
|
|
|
|
+ var casted = conn.create_command(
|
|
|
|
|
+ "SELECT :w::text AS t, :w AS w"
|
|
|
|
|
+ ).with_parameter("w", 9).execute_query().to_array();
|
|
|
|
|
+ assert(casted[0].get("t").try_get_as<string>(out s) && s == "9");
|
|
|
|
|
+
|
|
|
|
|
+ pass("placeholder edge cases");
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
void test_missing_parameter(Connection conn) throws SqlError {
|
|
void test_missing_parameter(Connection conn) throws SqlError {
|
|
|
print("Test: missing parameter rejected... ");
|
|
print("Test: missing parameter rejected... ");
|
|
|
try {
|
|
try {
|