Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add correct pagination for filters #335

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

hkdeman
Copy link
Contributor

@hkdeman hkdeman commented Jan 28, 2025

Fix: #281

Add total count for filter query to ensure that the pagination is correct.

Demo (shows filters has 3 pages with 15 total count on the filter):
image

WHERE database = '%s'
ORDER BY table, position
`, schema)

Check failure

Code scanning / CodeQL

Database query built from user-controlled sources High

This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
This query depends on a user-provided value.
This query depends on a user-provided value.

Copilot Autofix AI 5 days ago

To fix the problem, we should use parameterized queries or prepared statements to safely embed user input into SQL queries. This approach prevents SQL injection by ensuring that user input is treated as data rather than executable code.

In the provided code, we need to replace the use of fmt.Sprintf with parameterized queries using the QueryContext method. This involves modifying the getAllTableSchema and getTableSchema functions to use query parameters instead of directly embedding the schema and tableName values into the query string.

Suggested changeset 1
core/src/plugins/clickhouse/clickhouse.go

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/core/src/plugins/clickhouse/clickhouse.go b/core/src/plugins/clickhouse/clickhouse.go
--- a/core/src/plugins/clickhouse/clickhouse.go
+++ b/core/src/plugins/clickhouse/clickhouse.go
@@ -105,3 +105,3 @@
 func getAllTableSchema(conn *sql.DB, schema string) (map[string][]engine.Record, error) {
-	query := fmt.Sprintf(`
+	query := `
 		SELECT 
@@ -111,7 +111,7 @@
 		FROM system.columns
-		WHERE database = '%s'
+		WHERE database = ?
 		ORDER BY table, position
-	`, schema)
+	`
 
-	rows, err := conn.QueryContext(context.Background(), query)
+	rows, err := conn.QueryContext(context.Background(), query, schema)
 	if err != nil {
@@ -134,3 +134,3 @@
 func getTableSchema(conn *sql.DB, schema string, tableName string) ([]engine.Record, error) {
-	query := fmt.Sprintf(`
+	query := `
 		SELECT 
@@ -139,7 +139,7 @@
 		FROM system.columns
-		WHERE database = '%s' AND table = '%s'
+		WHERE database = ? AND table = ?
 		ORDER BY position
-	`, schema, tableName)
+	`
 
-	rows, err := conn.QueryContext(context.Background(), query)
+	rows, err := conn.QueryContext(context.Background(), query, schema, tableName)
 	if err != nil {
EOF
@@ -105,3 +105,3 @@
func getAllTableSchema(conn *sql.DB, schema string) (map[string][]engine.Record, error) {
query := fmt.Sprintf(`
query := `
SELECT
@@ -111,7 +111,7 @@
FROM system.columns
WHERE database = '%s'
WHERE database = ?
ORDER BY table, position
`, schema)
`

rows, err := conn.QueryContext(context.Background(), query)
rows, err := conn.QueryContext(context.Background(), query, schema)
if err != nil {
@@ -134,3 +134,3 @@
func getTableSchema(conn *sql.DB, schema string, tableName string) ([]engine.Record, error) {
query := fmt.Sprintf(`
query := `
SELECT
@@ -139,7 +139,7 @@
FROM system.columns
WHERE database = '%s' AND table = '%s'
WHERE database = ? AND table = ?
ORDER BY position
`, schema, tableName)
`

rows, err := conn.QueryContext(context.Background(), query)
rows, err := conn.QueryContext(context.Background(), query, schema, tableName)
if err != nil {
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options

countQuery := fmt.Sprintf("SELECT COUNT(*) %v", baseQuery)
var totalCount int
err = db.Raw(countQuery).Scan(&totalCount).Error

Check failure

Code scanning / CodeQL

Database query built from user-controlled sources High

This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
This query depends on a
user-provided value
.

Copilot Autofix AI 5 days ago

To fix the problem, we need to replace the unsafe construction of SQL queries using fmt.Sprintf with parameterized queries. This involves using placeholders in the SQL query and passing the user-provided values as separate arguments to the query execution function. This approach ensures that the user-provided values are properly escaped and prevents SQL injection attacks.

In the core/src/plugins/mysql/mysql.go file, we need to:

  1. Replace the fmt.Sprintf calls with parameterized queries.
  2. Pass the user-provided values as arguments to the db.Raw function.
Suggested changeset 1
core/src/plugins/mysql/mysql.go

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/core/src/plugins/mysql/mysql.go b/core/src/plugins/mysql/mysql.go
--- a/core/src/plugins/mysql/mysql.go
+++ b/core/src/plugins/mysql/mysql.go
@@ -119,10 +119,10 @@
 
-	query := fmt.Sprintf(`
+	query := `
 		SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE
 		FROM INFORMATION_SCHEMA.COLUMNS
-		WHERE TABLE_SCHEMA = '%v'
+		WHERE TABLE_SCHEMA = ?
 		ORDER BY TABLE_NAME, ORDINAL_POSITION
-	`, schema)
+	`
 
-	if err := db.Raw(query).Scan(&result).Error; err != nil {
+	if err := db.Raw(query, schema).Scan(&result).Error; err != nil {
 		return nil, err
@@ -144,10 +144,11 @@
 
-	baseQuery := fmt.Sprintf("FROM `%v`.`%s`", schema, storageUnit)
+	baseQuery := "FROM `?`.`?`"
+	args := []interface{}{schema, storageUnit}
 	if len(where) > 0 {
-		baseQuery = fmt.Sprintf("%v WHERE %v", baseQuery, where)
+		baseQuery += " WHERE " + where
 	}
 
-	countQuery := fmt.Sprintf("SELECT COUNT(*) %v", baseQuery)
+	countQuery := "SELECT COUNT(*) " + baseQuery
 	var totalCount int
-	err = db.Raw(countQuery).Scan(&totalCount).Error
+	err = db.Raw(countQuery, args...).Scan(&totalCount).Error
 	if err != nil {
@@ -156,5 +157,6 @@
 
-	query := fmt.Sprintf("SELECT * %v LIMIT ? OFFSET ?", baseQuery)
+	query := "SELECT * " + baseQuery + " LIMIT ? OFFSET ?"
+	args = append(args, pageSize, pageOffset)
 
-	result, err := p.executeRawSQL(config, query, pageSize, pageOffset)
+	result, err := p.executeRawSQL(config, query, args...)
 	if err != nil {
EOF
@@ -119,10 +119,10 @@

query := fmt.Sprintf(`
query := `
SELECT TABLE_NAME, COLUMN_NAME, DATA_TYPE
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_SCHEMA = '%v'
WHERE TABLE_SCHEMA = ?
ORDER BY TABLE_NAME, ORDINAL_POSITION
`, schema)
`

if err := db.Raw(query).Scan(&result).Error; err != nil {
if err := db.Raw(query, schema).Scan(&result).Error; err != nil {
return nil, err
@@ -144,10 +144,11 @@

baseQuery := fmt.Sprintf("FROM `%v`.`%s`", schema, storageUnit)
baseQuery := "FROM `?`.`?`"
args := []interface{}{schema, storageUnit}
if len(where) > 0 {
baseQuery = fmt.Sprintf("%v WHERE %v", baseQuery, where)
baseQuery += " WHERE " + where
}

countQuery := fmt.Sprintf("SELECT COUNT(*) %v", baseQuery)
countQuery := "SELECT COUNT(*) " + baseQuery
var totalCount int
err = db.Raw(countQuery).Scan(&totalCount).Error
err = db.Raw(countQuery, args...).Scan(&totalCount).Error
if err != nil {
@@ -156,5 +157,6 @@

query := fmt.Sprintf("SELECT * %v LIMIT ? OFFSET ?", baseQuery)
query := "SELECT * " + baseQuery + " LIMIT ? OFFSET ?"
args = append(args, pageSize, pageOffset)

result, err := p.executeRawSQL(config, query, pageSize, pageOffset)
result, err := p.executeRawSQL(config, query, args...)
if err != nil {
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options

countQuery := fmt.Sprintf("SELECT COUNT(*) %v", baseQuery)
var totalCount int
err = db.Raw(countQuery).Scan(&totalCount).Error

Check failure

Code scanning / CodeQL

Database query built from user-controlled sources High

This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
This query depends on a
user-provided value
.
This query depends on a
user-provided value
.

Copilot Autofix AI 5 days ago

To fix the problem, we need to use SQL parameterization instead of string concatenation to construct the SQL queries. This can be achieved by using placeholders (?) in the SQL query and passing the user-provided values as parameters to the db.Raw method. This approach ensures that the user-provided values are safely embedded into the query, preventing SQL injection attacks.

  1. Modify the GetRows method in core/src/plugins/postgres/postgres.go to use SQL parameterization.
  2. Replace the fmt.Sprintf calls with parameterized queries.
  3. Pass the user-provided values as parameters to the db.Raw method.
Suggested changeset 1
core/src/plugins/postgres/postgres.go

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/core/src/plugins/postgres/postgres.go b/core/src/plugins/postgres/postgres.go
--- a/core/src/plugins/postgres/postgres.go
+++ b/core/src/plugins/postgres/postgres.go
@@ -170,10 +170,10 @@
 
-	baseQuery := fmt.Sprintf("FROM \"%v\".\"%s\"", schema, storageUnit)
+	baseQuery := "FROM ?.? "
 	if len(where) > 0 {
-		baseQuery = fmt.Sprintf("%v WHERE %v", baseQuery, where)
+		baseQuery += "WHERE " + where + " "
 	}
 
-	countQuery := fmt.Sprintf("SELECT COUNT(*) %v", baseQuery)
+	countQuery := "SELECT COUNT(*) " + baseQuery
 	var totalCount int
-	err = db.Raw(countQuery).Scan(&totalCount).Error
+	err = db.Raw(countQuery, schema, storageUnit).Scan(&totalCount).Error
 	if err != nil {
@@ -182,3 +182,3 @@
 
-	query := fmt.Sprintf("SELECT * %v", baseQuery)
+	query := "SELECT * " + baseQuery
 	sortKeyRes, err := getPrimaryKeyColumns(db, schema, storageUnit)
@@ -186,8 +186,8 @@
 		quotedKeys := common.JoinWithQuotes(sortKeyRes)
-		query = fmt.Sprintf("%v ORDER BY %v ASC", query, quotedKeys)
+		query += "ORDER BY " + quotedKeys + " ASC "
 	}
 
-	query = fmt.Sprintf("%v LIMIT ? OFFSET ?", query)
+	query += "LIMIT ? OFFSET ?"
 
-	result, err := p.executeRawSQL(config, query, pageSize, pageOffset)
+	result, err := p.executeRawSQL(config, query, schema, storageUnit, pageSize, pageOffset)
 	if err != nil {
EOF
@@ -170,10 +170,10 @@

baseQuery := fmt.Sprintf("FROM \"%v\".\"%s\"", schema, storageUnit)
baseQuery := "FROM ?.? "
if len(where) > 0 {
baseQuery = fmt.Sprintf("%v WHERE %v", baseQuery, where)
baseQuery += "WHERE " + where + " "
}

countQuery := fmt.Sprintf("SELECT COUNT(*) %v", baseQuery)
countQuery := "SELECT COUNT(*) " + baseQuery
var totalCount int
err = db.Raw(countQuery).Scan(&totalCount).Error
err = db.Raw(countQuery, schema, storageUnit).Scan(&totalCount).Error
if err != nil {
@@ -182,3 +182,3 @@

query := fmt.Sprintf("SELECT * %v", baseQuery)
query := "SELECT * " + baseQuery
sortKeyRes, err := getPrimaryKeyColumns(db, schema, storageUnit)
@@ -186,8 +186,8 @@
quotedKeys := common.JoinWithQuotes(sortKeyRes)
query = fmt.Sprintf("%v ORDER BY %v ASC", query, quotedKeys)
query += "ORDER BY " + quotedKeys + " ASC "
}

query = fmt.Sprintf("%v LIMIT ? OFFSET ?", query)
query += "LIMIT ? OFFSET ?"

result, err := p.executeRawSQL(config, query, pageSize, pageOffset)
result, err := p.executeRawSQL(config, query, schema, storageUnit, pageSize, pageOffset)
if err != nil {
Copilot is powered by AI and may make mistakes. Always verify output.
Positive Feedback
Negative Feedback

Provide additional feedback

Please help us improve GitHub Copilot by sharing more details about this comment.

Please select one or more of the options
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] - Filter, number of pages stays the same
1 participant