Skip to content

Commit

Permalink
fix: always escape table name or table alias in sql queries
Browse files Browse the repository at this point in the history
  • Loading branch information
SandPod committed Oct 10, 2023
1 parent 0394b56 commit b4b4c3e
Show file tree
Hide file tree
Showing 17 changed files with 65 additions and 64 deletions.
2 changes: 1 addition & 1 deletion packages/serverpod/lib/src/database/columns.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ abstract class Column<T> {

@override
String toString() {
return '${table.queryPrefix}."$_columnName"';
return '"${table.queryPrefix}"."$_columnName"';
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/serverpod/lib/src/database/database_query.dart
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ String _joinStatementFromJoinContexts(
joinStatement += ' "${tableRelation.lastForeignTableName}" AS';
}

joinStatement += ' ${tableRelation.relationQueryAlias} '
joinStatement += ' "${tableRelation.relationQueryAlias}" '
'ON ${tableRelation.lastJoiningField} ';

if (!joinContext.subQuery) {
Expand All @@ -495,7 +495,7 @@ _UsingQuery _usingQueryFromJoinContexts(
for (var joinContext in joinContexts.values) {
var tableRelation = joinContext.tableRelation;
usingStatements.add(
'"${tableRelation.lastForeignTableName}" AS ${tableRelation.relationQueryAlias}');
'"${tableRelation.lastForeignTableName}" AS "${tableRelation.relationQueryAlias}"');
whereStatements.add(
'${tableRelation.lastJoiningField} = ${tableRelation.lastJoiningForeignField}');
}
Expand Down
4 changes: 2 additions & 2 deletions packages/serverpod/lib/src/database/table_relation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ class TableRelation {

/// Name of the last field to be joined.
String get lastJoiningField {
return '${_fromRelationQueryAlias()}."${_tableRelationEntries.last.field.columnName}"';
return '"${_fromRelationQueryAlias()}"."${_tableRelationEntries.last.field.columnName}"';
}

/// Name of the last foreign field to be joined.
String get lastJoiningForeignField {
return '${_buildRelationQueryAlias()}."${_tableRelationEntries.last.foreignField.columnName}"';
return '"${_buildRelationQueryAlias()}"."${_tableRelationEntries.last.foreignField.columnName}"';
}

/// Name of the last foreign field to be joined as query alias.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void main() {
test(
'when toString is called then column name withing double quotes is returned.',
() {
expect(column.toString(), 'test."$columnName"');
expect(column.toString(), '"test"."$columnName"');
});

test('when columnName getter is called then column name is returned.', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ void main() {
test(
'when toString is called then column name withing double quotes is returned.',
() {
expect(column.toString(), 'test."$columnName"');
expect(column.toString(), '"test"."$columnName"');
});

test('when columnName getter is called then column name is returned.', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void main() {
test(
'when toString is called then column name withing double quotes is returned.',
() {
expect(column.toString(), 'test."$columnName"');
expect(column.toString(), '"test"."$columnName"');
});

test('when columnName getter is called then column name is returned.', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void main() {
test(
'when toString is called then column name withing double quotes is returned.',
() {
expect(column.toString(), 'test."$columnName"');
expect(column.toString(), '"test"."$columnName"');
});

test('when columnName getter is called then column name is returned.', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void main() {
test(
'when toString is called then column name withing double quotes is returned.',
() {
expect(column.toString(), 'test."$columnName"');
expect(column.toString(), '"test"."$columnName"');
});

test('when columnName getter is called then column name is returned.', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ void main() {
test(
'when toString is called then column name withing double quotes is returned.',
() {
expect(column.toString(), 'test."$columnName"');
expect(column.toString(), '"test"."$columnName"');
});

test('when columnName getter is called then column name is returned.', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void main() {
test(
'when toString is called then column name withing double quotes is returned.',
() {
expect(column.toString(), 'test."$columnName"');
expect(column.toString(), '"test"."$columnName"');
});

test('when columnName getter is called then column name is returned.', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void main() {
test(
'when toString is called then column name withing double quotes is returned.',
() {
expect(column.toString(), 'test."$columnName"');
expect(column.toString(), '"test"."$columnName"');
});

test('when columnName getter is called then column name is returned.', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void main() {
test(
'when toString is called then column name withing double quotes is returned.',
() {
expect(column.toString(), 'test."$columnName"');
expect(column.toString(), '"test"."$columnName"');
});

test('when columnName getter is called then column name is returned.', () {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void main() {
test(
'when toString is called then column name withing double quotes is returned.',
() {
expect(column.toString(), 'test."$columnName"');
expect(column.toString(), '"test"."$columnName"');
});

test('when columnName getter is called then column name is returned.', () {
Expand Down
58 changes: 29 additions & 29 deletions packages/serverpod/test/database/database_query_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ void main() {
test('when default initialized then build outputs a valid SQL query.', () {
var query = SelectQueryBuilder(table: citizenTable).build();

expect(query, 'SELECT citizen."id" AS "citizen.id" FROM "citizen"');
expect(query, 'SELECT "citizen"."id" AS "citizen.id" FROM "citizen"');
});

test('when query with specific fields is built then output selects fields.',
Expand All @@ -96,7 +96,7 @@ void main() {
.build();

expect(query,
'SELECT citizen."id" AS "citizen.id", citizen."name" AS "citizen.name", citizen."age" AS "citizen.age" FROM "citizen"');
'SELECT "citizen"."id" AS "citizen.id", "citizen"."name" AS "citizen.name", "citizen"."age" AS "citizen.age" FROM "citizen"');
});

test(
Expand All @@ -107,7 +107,7 @@ void main() {
.build();

expect(query,
'SELECT citizen."id" AS "citizen.id" FROM "citizen" WHERE "test"=@test');
'SELECT "citizen"."id" AS "citizen.id" FROM "citizen" WHERE "test"=@test');
});

test(
Expand All @@ -122,7 +122,7 @@ void main() {
.build();

expect(query,
'SELECT citizen."id" AS "citizen.id" FROM "citizen" WHERE (TRUE = TRUE AND FALSE = FALSE)');
'SELECT "citizen"."id" AS "citizen.id" FROM "citizen" WHERE (TRUE = TRUE AND FALSE = FALSE)');
});

test(
Expand All @@ -137,7 +137,7 @@ void main() {
SelectQueryBuilder(table: citizenTable).withOrderBy([order]).build();

expect(query,
'SELECT citizen."id" AS "citizen.id" FROM "citizen" ORDER BY citizen."id"');
'SELECT "citizen"."id" AS "citizen.id" FROM "citizen" ORDER BY "citizen"."id"');
});

test(
Expand All @@ -162,7 +162,7 @@ void main() {
SelectQueryBuilder(table: citizenTable).withOrderBy(orders).build();

expect(query,
'SELECT citizen."id" AS "citizen.id" FROM "citizen" ORDER BY citizen."id", citizen."name" DESC, citizen."age"');
'SELECT "citizen"."id" AS "citizen.id" FROM "citizen" ORDER BY "citizen"."id", "citizen"."name" DESC, "citizen"."age"');
});

test(
Expand All @@ -182,7 +182,7 @@ void main() {

expect(
query,
'SELECT citizen."id" AS "citizen.id" FROM "citizen" LEFT JOIN "citizen" AS citizen_friends_citizen ON citizen."id" = citizen_friends_citizen."id" GROUP BY "citizen.id" ORDER BY COUNT(citizen_friends_citizen."id")',
'SELECT "citizen"."id" AS "citizen.id" FROM "citizen" LEFT JOIN "citizen" AS "citizen_friends_citizen" ON "citizen"."id" = "citizen_friends_citizen"."id" GROUP BY "citizen.id" ORDER BY COUNT("citizen_friends_citizen"."id")',
);
});

Expand All @@ -202,7 +202,7 @@ void main() {
SelectQueryBuilder(table: citizenTable).withOrderBy([order]).build();

expect(query,
'WITH citizen_friends_citizen AS (SELECT citizen."id" AS "citizen.id" FROM "citizen" WHERE citizen."id" = 5) SELECT citizen."id" AS "citizen.id" FROM "citizen" LEFT JOIN citizen_friends_citizen ON citizen."id" = citizen_friends_citizen."citizen.id" GROUP BY "citizen.id" ORDER BY COUNT(citizen_friends_citizen."citizen.id")');
'WITH citizen_friends_citizen AS (SELECT "citizen"."id" AS "citizen.id" FROM "citizen" WHERE "citizen"."id" = 5) SELECT "citizen"."id" AS "citizen.id" FROM "citizen" LEFT JOIN "citizen_friends_citizen" ON "citizen"."id" = "citizen_friends_citizen"."citizen.id" GROUP BY "citizen.id" ORDER BY COUNT("citizen_friends_citizen"."citizen.id")');
});

test(
Expand Down Expand Up @@ -232,8 +232,8 @@ void main() {
test('when query with limit is built then output is query with limit.', () {
var query = SelectQueryBuilder(table: citizenTable).withLimit(10).build();

expect(
query, 'SELECT citizen."id" AS "citizen.id" FROM "citizen" LIMIT 10');
expect(query,
'SELECT "citizen"."id" AS "citizen.id" FROM "citizen" LIMIT 10');
});

test('when query with offset is built then output is query with offset.',
Expand All @@ -242,7 +242,7 @@ void main() {
SelectQueryBuilder(table: citizenTable).withOffset(10).build();

expect(query,
'SELECT citizen."id" AS "citizen.id" FROM "citizen" OFFSET 10');
'SELECT "citizen"."id" AS "citizen.id" FROM "citizen" OFFSET 10');
});

test(
Expand All @@ -264,7 +264,7 @@ void main() {
.build();

expect(query,
'SELECT citizen."id" AS "citizen.id" FROM "citizen" LEFT JOIN "company" AS citizen_company_company ON citizen."companyId" = citizen_company_company."id" WHERE citizen_company_company."name" = \'Serverpod\'');
'SELECT "citizen"."id" AS "citizen.id" FROM "citizen" LEFT JOIN "company" AS "citizen_company_company" ON "citizen"."companyId" = "citizen_company_company"."id" WHERE "citizen_company_company"."name" = \'Serverpod\'');
});

test(
Expand Down Expand Up @@ -294,7 +294,7 @@ void main() {
.build();

expect(query,
'SELECT citizen."id" AS "citizen.id" FROM "citizen" LEFT JOIN "company" AS citizen_company_company ON citizen."companyId" = citizen_company_company."id" LEFT JOIN "citizen" AS citizen_company_company_ceo_citizen ON citizen_company_company."ceoId" = citizen_company_company_ceo_citizen."id" WHERE citizen_company_company_ceo_citizen."name" = \'Alex\'');
'SELECT "citizen"."id" AS "citizen.id" FROM "citizen" LEFT JOIN "company" AS "citizen_company_company" ON "citizen"."companyId" = "citizen_company_company"."id" LEFT JOIN "citizen" AS "citizen_company_company_ceo_citizen" ON "citizen_company_company"."ceoId" = "citizen_company_company_ceo_citizen"."id" WHERE "citizen_company_company_ceo_citizen"."name" = \'Alex\'');
});

test('when all properties configured is built then output is valid SQL.',
Expand Down Expand Up @@ -329,7 +329,7 @@ void main() {
.build();

expect(query,
'SELECT citizen."id" AS "citizen.id", citizen."name" AS "citizen.name", citizen."age" AS "citizen.age" FROM "citizen" LEFT JOIN "company" AS citizen_company_company ON citizen."companyId" = citizen_company_company."id" WHERE citizen_company_company."name" = \'Serverpod\' ORDER BY citizen."id" DESC LIMIT 10 OFFSET 5');
'SELECT "citizen"."id" AS "citizen.id", "citizen"."name" AS "citizen.name", "citizen"."age" AS "citizen.age" FROM "citizen" LEFT JOIN "company" AS "citizen_company_company" ON "citizen"."companyId" = "citizen_company_company"."id" WHERE "citizen_company_company"."name" = \'Serverpod\' ORDER BY "citizen"."id" DESC LIMIT 10 OFFSET 5');
});

test(
Expand All @@ -344,7 +344,7 @@ void main() {
(e) => e.toString(),
'message',
equals(
'FormatException: Column references starting from other tables than "citizen" are not supported. The following expressions need to be removed or modified:\n"where" expression referencing column company."name".'),
'FormatException: Column references starting from other tables than "citizen" are not supported. The following expressions need to be removed or modified:\n"where" expression referencing column "company"."name".'),
)));
});

Expand All @@ -359,7 +359,7 @@ void main() {
(e) => e.toString(),
'message',
equals(
'FormatException: Column references starting from other tables than "citizen" are not supported. The following expressions need to be removed or modified:\n"orderBy" expression referencing column company."name".'),
'FormatException: Column references starting from other tables than "citizen" are not supported. The following expressions need to be removed or modified:\n"orderBy" expression referencing column "company"."name".'),
)));
});

Expand All @@ -386,14 +386,14 @@ void main() {
test('when default initialized then build outputs a valid SQL query.', () {
var query = CountQueryBuilder(table: citizenTable).build();

expect(query, 'SELECT COUNT(citizen."id") FROM "citizen"');
expect(query, 'SELECT COUNT("citizen"."id") FROM "citizen"');
});
test('when query with alias is built then count result has defined alias.',
() {
var query =
CountQueryBuilder(table: citizenTable).withCountAlias('c').build();

expect(query, 'SELECT COUNT(citizen."id") AS c FROM "citizen"');
expect(query, 'SELECT COUNT("citizen"."id") AS c FROM "citizen"');
});

test('when query with field is built then count is based on that field.',
Expand All @@ -402,7 +402,7 @@ void main() {
.withField(ColumnInt('age', citizenTable))
.build();

expect(query, 'SELECT COUNT(citizen."age") FROM "citizen"');
expect(query, 'SELECT COUNT("citizen"."age") FROM "citizen"');
});

test(
Expand All @@ -413,14 +413,14 @@ void main() {
.build();

expect(query,
'SELECT COUNT(citizen."id") FROM "citizen" WHERE "test"=@test');
'SELECT COUNT("citizen"."id") FROM "citizen" WHERE "test"=@test');
});

test('when query with limit is built then output is a query with limit.',
() {
var query = CountQueryBuilder(table: citizenTable).withLimit(10).build();

expect(query, 'SELECT COUNT(citizen."id") FROM "citizen" LIMIT 10');
expect(query, 'SELECT COUNT("citizen"."id") FROM "citizen" LIMIT 10');
});

test(
Expand All @@ -445,7 +445,7 @@ void main() {
.build();

expect(query,
'SELECT COUNT(citizen."id") FROM "citizen" LEFT JOIN "company" AS citizen_company_company ON citizen."companyId" = citizen_company_company."id" WHERE citizen_company_company."name" = \'Serverpod\'');
'SELECT COUNT("citizen"."id") FROM "citizen" LEFT JOIN "company" AS "citizen_company_company" ON "citizen"."companyId" = "citizen_company_company"."id" WHERE "citizen_company_company"."name" = \'Serverpod\'');
});

test(
Expand Down Expand Up @@ -475,7 +475,7 @@ void main() {
.build();

expect(query,
'SELECT COUNT(citizen."id") FROM "citizen" LEFT JOIN "company" AS citizen_company_company ON citizen."companyId" = citizen_company_company."id" LEFT JOIN "citizen" AS citizen_company_company_ceo_citizen ON citizen_company_company."ceoId" = citizen_company_company_ceo_citizen."id" WHERE citizen_company_company_ceo_citizen."name" = \'Alex\'');
'SELECT COUNT("citizen"."id") FROM "citizen" LEFT JOIN "company" AS "citizen_company_company" ON "citizen"."companyId" = "citizen_company_company"."id" LEFT JOIN "citizen" AS "citizen_company_company_ceo_citizen" ON "citizen_company_company"."ceoId" = "citizen_company_company_ceo_citizen"."id" WHERE "citizen_company_company_ceo_citizen"."name" = \'Alex\'');
});

test(
Expand All @@ -502,7 +502,7 @@ void main() {
.build();

expect(query,
'SELECT COUNT(citizen."age") AS c FROM "citizen" LEFT JOIN "company" AS citizen_company_company ON citizen."companyId" = citizen_company_company."id" WHERE citizen_company_company."name" = \'Serverpod\' LIMIT 10');
'SELECT COUNT("citizen"."age") AS c FROM "citizen" LEFT JOIN "company" AS "citizen_company_company" ON "citizen"."companyId" = "citizen_company_company"."id" WHERE "citizen_company_company"."name" = \'Serverpod\' LIMIT 10');
});

test(
Expand All @@ -517,7 +517,7 @@ void main() {
(e) => e.toString(),
'message',
equals(
'FormatException: Column references starting from other tables than "citizen" are not supported. The following expressions need to be removed or modified:\n"where" expression referencing column company."name".'),
'FormatException: Column references starting from other tables than "citizen" are not supported. The following expressions need to be removed or modified:\n"where" expression referencing column "company"."name".'),
)));
});

Expand Down Expand Up @@ -594,7 +594,7 @@ void main() {
.build();

expect(query,
'DELETE FROM "citizen" USING "company" AS citizen_company_company WHERE citizen_company_company."name" = \'Serverpod\' AND citizen."companyId" = citizen_company_company."id"');
'DELETE FROM "citizen" USING "company" AS "citizen_company_company" WHERE "citizen_company_company"."name" = \'Serverpod\' AND "citizen"."companyId" = "citizen_company_company"."id"');
});

test(
Expand All @@ -621,7 +621,7 @@ void main() {
.build();

expect(query,
'DELETE FROM "citizen" USING "company" AS citizen_company_company, "citizen" AS citizen_company_company_ceo_citizen WHERE citizen_company_company_ceo_citizen."name" = \'Alex\' AND citizen."companyId" = citizen_company_company."id" AND citizen_company_company."ceoId" = citizen_company_company_ceo_citizen."id"');
'DELETE FROM "citizen" USING "company" AS "citizen_company_company", "citizen" AS "citizen_company_company_ceo_citizen" WHERE "citizen_company_company_ceo_citizen"."name" = \'Alex\' AND "citizen"."companyId" = "citizen_company_company"."id" AND "citizen_company_company"."ceoId" = "citizen_company_company_ceo_citizen"."id"');
});

test(
Expand All @@ -644,7 +644,7 @@ void main() {
.build();

expect(query,
'DELETE FROM "citizen" USING "company" AS citizen_company_company WHERE citizen_company_company."name" = \'Serverpod\' AND citizen."companyId" = citizen_company_company."id" RETURNING *');
'DELETE FROM "citizen" USING "company" AS "citizen_company_company" WHERE "citizen_company_company"."name" = \'Serverpod\' AND "citizen"."companyId" = "citizen_company_company"."id" RETURNING *');
});

test(
Expand All @@ -659,7 +659,7 @@ void main() {
(e) => e.toString(),
'message',
equals(
'FormatException: Column references starting from other tables than "citizen" are not supported. The following expressions need to be removed or modified:\n"where" expression referencing column company."name".'),
'FormatException: Column references starting from other tables than "citizen" are not supported. The following expressions need to be removed or modified:\n"where" expression referencing column "company"."name".'),
)));
});

Expand Down
Loading

0 comments on commit b4b4c3e

Please sign in to comment.