squirrel icon indicating copy to clipboard operation
squirrel copied to clipboard

Where with parametrized INTERVAL

Open ikawalec opened this issue 1 year ago • 9 comments

Hi,

I'm having an issue with using where expr with parametrized INTERVAL.

Code:

d := 3

builder := r.StatementBuilderType.
  Delete("test").
  Where(squirrel.Expr("expiry <= now()::timestamptz - INTERVAL '? DAYS'", d))
		
query, args, err = builder.ToSql()
	
logrus.Infof("query: %s, args: %+v", query, args)
	
// db execute

I'm getting the following error:

ERROR: could not parse "$1 DAYS" as type interval: interval: missing number at position 0: "$1 DAYS" (SQLSTATE 22007)

Generated query and args:

query: DELETE FROM test WHERE expiry \u003c= now()::timestamptz - INTERVAL '$1 DAYS'
args: [3]

Expected SQL:

delete from test where expiry <= now()::timestamptz - INTERVAL '3 days';

Is this a bug? Is there any other way this can be achieved?

Thanks!

ikawalec avatar May 28 '24 09:05 ikawalec

Assuming you are using postgres, I believe the quotes are the problem: INTERVAL '? DAYS' -> INTERVAL ? DAYS

lann avatar May 28 '24 13:05 lann

Assuming you are using postgres, I believe the quotes are the problem: INTERVAL '? DAYS' -> INTERVAL ? DAYS

That's correct, I'm using postgres. Without quotes, it's not a valid SQL statement:

delete from test where expiry <= now()::timestamptz - INTERVAL 3 days;

at or near "3": syntax error
DETAIL:  source SQL:
delete from test where expiry <= now()::timestamptz - INTERVAL 3 days

ikawalec avatar May 28 '24 14:05 ikawalec

It looks like postgres expects the number to be a string, so you may also need to e.g. strconv.Itoa the Go int before passing it to the database.

lann avatar May 28 '24 15:05 lann

Thanks but still even with days converted usingstrconv.Itoa I still get the same error (assuming quotes are mandatory).

squirrel.Expr("expiry <= now()::timestamptz - INTERVAL '? DAYS'", strconv.Itoa(days)),
ERROR: could not parse "$1 DAYS" as type interval: interval: missing number at position 0: "$1 DAYS" (SQLSTATE 22007)

ikawalec avatar May 28 '24 17:05 ikawalec

The quotes mean you are passing the literal string "? DAYS"; Squirrel converts the ? to $1 because its placeholder replacement doesn't know how to deal with strings.

I believe what you need is:

squirrel.Expr("expiry <= now()::timestamptz - INTERVAL ? DAYS", strconv.Itoa(days)),

lann avatar May 28 '24 17:05 lann

The quotes mean you are passing the literal string "? DAYS"; Squirrel converts the ? to $1 because its placeholder replacement doesn't know how to deal with strings.

I believe what you need is:

squirrel.Expr("expiry <= now()::timestamptz - INTERVAL ? DAYS", strconv.Itoa(days)),

The example that you provided will generate the following SQL query:

DELETE FROM test WHERE expiry \u003c= now()::timestamptz - INTERVAL 3 DAYS

In order for that to work with postgres: https://www.postgresql.org/docs/8.0/functions-datetime.html, the INTERVAL should use quotes '3 DAYS':

DELETE FROM test WHERE expiry \u003c= now()::timestamptz - INTERVAL '3 DAYS'

ikawalec avatar May 28 '24 20:05 ikawalec

Ah sorry, I got bad information from Google. In that case I would expect something like this to work:

squirrel.Expr("expiry <= now()::timestamptz - INTERVAL ?", fmt.Sprintf("%d DAYS", days))

lann avatar May 28 '24 21:05 lann

Ah sorry, I got bad information from Google. In that case I would expect something like this to work:

squirrel.Expr("expiry <= now()::timestamptz - INTERVAL ?", fmt.Sprintf("%d DAYS", days))

Unfortunately, this would also fail:

 query: DELETE FROM test WHERE expiry \u003c= now()::timestamptz - INTERVAL $1
 args: [3 DAYS]
 error: ERROR: at or near "1": syntax error (SQLSTATE 42601)

ikawalec avatar May 29 '24 07:05 ikawalec

Only way I've gotten this to work is by doing something such as the following

Where(`"timestamp" >= (recent_close."timestamp" - interval '1 day' * ?)`, finalInterval)

Where finalInterval is a number.

The key part being the multiplier, unfortunately seems like a driver issue.

efitzkiwi avatar Aug 06 '24 21:08 efitzkiwi