While @vonPryz' answer is correct insofar as the sequencing (i.e. the evaluation-order) of predicate terms in a WHERE clause is not within the query author's control, it is still possible to use other T-SQL language features to ensure safety and correctness.
But I do note that your particular issue only happens with a statically defined T-SQL variable - which means it's your responsibility to add an IF guard to your entire SELECT query:
Or rather: Don't execute a query that will fail when your @variables are invalid, like so:
DECLARE @textToSearch NVARCHAR(500) = N'';
IF( @textToSearch IS NOT NULL AND LEN( @textToSearch ) > 0 )
BEGIN;
SELECT
pd."Description"
FROM
SalesLT.ProductDescription AS pd
WHERE
LEN( COALESCE( @textToSearch, N'' ) ) > 0 /*Condition1*/
AND
CONTAINS( pd."Description", @textToSearch ); /*Condition2*/
END;
/* Optionally, you may want to execute a query that always returns zero rows but with the same column-schema (names, datatypes, nullability, etc) to ensure any consumers won't break due to assumptions about resultset existence or ordering:
...like so:
*/
ELSE
BEGIN
SELECT
N'' AS "Description"
FROM
( VALUES (1) ) AS dummy( a )
WHERE
dummy.a = 0;
END;
But if your arguments to CONTAINS are not variables, but just column-expressions inside a SELECT, then the solutions (or workarounds) are different.
Supposing you have this as your current query, which will fail similarly to your current query when otherTable.KnownSubstring is not NULL but still empty because the CONTAINS function requires nonempty arguments:
SELECT
pd.Description
FROM
SalesLT.ProductDescription AS pd
INNER JOIN otherTable AS ot ON pd.Foo = ot.Bar
WHERE
LEN( COALESCE( ot.KnownSubstring, N'' ) ) > 0 /*Condition1*/
AND
CONTAINS( pd.Description, ot.KnownSubstring ); /*Condition2*/
...in which case use a derived table (inner subquery) or CTE to initially filter out invalid rows:
WITH validJoinedRows AS (
SELECT
pd.*
ot.*
FROM
SalesLT.ProductDescription AS pd
INNER JOIN otherTable AS ot ON pd.Foo = ot.Bar
WHERE
ot.KnownSubstring IS NOT NULL
AND
LEN( ot.KnownSubstring ) > 0
AND
pd.Description IS NOT NULL
)
SELECT
vj."Description"
FROM
validJoinedRows AS vj
WHERE
CONTAINS( vj.Description, vj.KnownSubstring );