fix: ExplainSQL using consecutive pairs of escaper in SQL string represents an escaper (#6766)
Preventing it from being interpreted as the string terminator. This is a widely used escape mechanism in SQL standards and is applicable in most relational databases.
This commit is contained in:
		
							parent
							
								
									436cca753c
								
							
						
					
					
						commit
						87decced23
					
				| @ -79,17 +79,17 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a | |||||||
| 			case reflect.Bool: | 			case reflect.Bool: | ||||||
| 				vars[idx] = fmt.Sprintf("%t", reflectValue.Interface()) | 				vars[idx] = fmt.Sprintf("%t", reflectValue.Interface()) | ||||||
| 			case reflect.String: | 			case reflect.String: | ||||||
| 				vars[idx] = escaper + strings.ReplaceAll(fmt.Sprintf("%v", v), escaper, "\\"+escaper) + escaper | 				vars[idx] = escaper + strings.ReplaceAll(fmt.Sprintf("%v", v), escaper, escaper+escaper) + escaper | ||||||
| 			default: | 			default: | ||||||
| 				if v != nil && reflectValue.IsValid() && ((reflectValue.Kind() == reflect.Ptr && !reflectValue.IsNil()) || reflectValue.Kind() != reflect.Ptr) { | 				if v != nil && reflectValue.IsValid() && ((reflectValue.Kind() == reflect.Ptr && !reflectValue.IsNil()) || reflectValue.Kind() != reflect.Ptr) { | ||||||
| 					vars[idx] = escaper + strings.ReplaceAll(fmt.Sprintf("%v", v), escaper, "\\"+escaper) + escaper | 					vars[idx] = escaper + strings.ReplaceAll(fmt.Sprintf("%v", v), escaper, escaper+escaper) + escaper | ||||||
| 				} else { | 				} else { | ||||||
| 					vars[idx] = nullStr | 					vars[idx] = nullStr | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		case []byte: | 		case []byte: | ||||||
| 			if s := string(v); isPrintable(s) { | 			if s := string(v); isPrintable(s) { | ||||||
| 				vars[idx] = escaper + strings.ReplaceAll(s, escaper, "\\"+escaper) + escaper | 				vars[idx] = escaper + strings.ReplaceAll(s, escaper, escaper+escaper) + escaper | ||||||
| 			} else { | 			} else { | ||||||
| 				vars[idx] = escaper + "<binary>" + escaper | 				vars[idx] = escaper + "<binary>" + escaper | ||||||
| 			} | 			} | ||||||
| @ -100,7 +100,7 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a | |||||||
| 		case float64: | 		case float64: | ||||||
| 			vars[idx] = strconv.FormatFloat(v, 'f', -1, 64) | 			vars[idx] = strconv.FormatFloat(v, 'f', -1, 64) | ||||||
| 		case string: | 		case string: | ||||||
| 			vars[idx] = escaper + strings.ReplaceAll(v, escaper, "\\"+escaper) + escaper | 			vars[idx] = escaper + strings.ReplaceAll(v, escaper, escaper+escaper) + escaper | ||||||
| 		default: | 		default: | ||||||
| 			rv := reflect.ValueOf(v) | 			rv := reflect.ValueOf(v) | ||||||
| 			if v == nil || !rv.IsValid() || rv.Kind() == reflect.Ptr && rv.IsNil() { | 			if v == nil || !rv.IsValid() || rv.Kind() == reflect.Ptr && rv.IsNil() { | ||||||
| @ -117,7 +117,7 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a | |||||||
| 						return | 						return | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				vars[idx] = escaper + strings.ReplaceAll(fmt.Sprint(v), escaper, "\\"+escaper) + escaper | 				vars[idx] = escaper + strings.ReplaceAll(fmt.Sprint(v), escaper, escaper+escaper) + escaper | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ func (s ExampleStruct) Value() (driver.Value, error) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func format(v []byte, escaper string) string { | func format(v []byte, escaper string) string { | ||||||
| 	return escaper + strings.ReplaceAll(string(v), escaper, "\\"+escaper) + escaper | 	return escaper + strings.ReplaceAll(string(v), escaper, escaper+escaper) + escaper | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestExplainSQL(t *testing.T) { | func TestExplainSQL(t *testing.T) { | ||||||
| @ -40,7 +40,7 @@ func TestExplainSQL(t *testing.T) { | |||||||
| 	var ( | 	var ( | ||||||
| 		tt     = now.MustParse("2020-02-23 11:10:10") | 		tt     = now.MustParse("2020-02-23 11:10:10") | ||||||
| 		myrole = role("admin") | 		myrole = role("admin") | ||||||
| 		pwd    = password([]byte("pass")) | 		pwd    = password("pass") | ||||||
| 		jsVal  = []byte(`{"Name":"test","Val":"test"}`) | 		jsVal  = []byte(`{"Name":"test","Val":"test"}`) | ||||||
| 		js     = JSON(jsVal) | 		js     = JSON(jsVal) | ||||||
| 		esVal  = []byte(`{"Name":"test","Val":"test"}`) | 		esVal  = []byte(`{"Name":"test","Val":"test"}`) | ||||||
| @ -57,13 +57,13 @@ func TestExplainSQL(t *testing.T) { | |||||||
| 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | ||||||
| 			NumericRegexp: nil, | 			NumericRegexp: nil, | ||||||
| 			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd}, | 			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd}, | ||||||
| 			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass")`, | 			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.""com", "admin", "pass")`, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | ||||||
| 			NumericRegexp: nil, | 			NumericRegexp: nil, | ||||||
| 			Vars:          []interface{}{"jinzhu?", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd}, | 			Vars:          []interface{}{"jinzhu?", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd}, | ||||||
| 			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu?", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass")`, | 			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu?", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.""com", "admin", "pass")`, | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (@p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11)", | 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (@p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11)", | ||||||
| @ -87,25 +87,25 @@ func TestExplainSQL(t *testing.T) { | |||||||
| 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | ||||||
| 			NumericRegexp: nil, | 			NumericRegexp: nil, | ||||||
| 			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, js, es}, | 			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, js, es}, | ||||||
| 			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), | 			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.""com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | ||||||
| 			NumericRegexp: nil, | 			NumericRegexp: nil, | ||||||
| 			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es}, | 			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es}, | ||||||
| 			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), | 			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.""com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | ||||||
| 			NumericRegexp: nil, | 			NumericRegexp: nil, | ||||||
| 			Vars:          []interface{}{"jinzhu", 1, 0.1753607109, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es}, | 			Vars:          []interface{}{"jinzhu", 1, 0.1753607109, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es}, | ||||||
| 			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 0.1753607109, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), | 			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 0.1753607109, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.""com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), | ||||||
| 		}, | 		}, | ||||||
| 		{ | 		{ | ||||||
| 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", | ||||||
| 			NumericRegexp: nil, | 			NumericRegexp: nil, | ||||||
| 			Vars:          []interface{}{"jinzhu", 1, float32(999.99), true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es}, | 			Vars:          []interface{}{"jinzhu", 1, float32(999.99), true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es}, | ||||||
| 			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), | 			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.""com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)), | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 iTanken
						iTanken