Developer forum

Forum » Development » Exception in assortment handling

Exception in assortment handling

Anders Ebdrup
Anders Ebdrup
Reply

Hi Dynamicweb,

 

We have a critical error in the assortment handling for 9.6.6.

In GetProductSql we have this code section:

                If Not IsNothing(user) Then
                    Dim assortments As IEnumerable(Of String) = Services.Assortments.GetAssortmentIdsByUser(user).ToArray()
                    query.Add(" AND ( ( AssortmentItems.AssortmentItemAssortmentID IN ( {0} ) ", If(assortments.Any, assortments, String.Empty))
                Else
                    Dim assortments As IEnumerable(Of String) = Services.Assortments.GetAllowAnonymousUsersAssortmentIds().ToArray()
                    query.Add(" AND ( ( AssortmentItems.AssortmentItemAssortmentID IN ( {0} ) ", If(assortments.Any, assortments, String.Empty))
                End If
                Dim notActiveAssortments = Services.Assortments.GetNotActiveAssortmentIds()
                If notActiveAssortments.Any() Then
                    query.Add(" OR ( AssortmentItems.AssortmentItemAssortmentID IN ( {0} )  ", notActiveAssortments.ToArray())
                    query.Add(" AND AssortmentItems.AssortmentItemProductID NOT IN (SELECT AssortmentItemProductID FROM EcomAssortmentItems WHERE AssortmentItemAssortmentID IN ({0})) ) )", Services.Assortments.GetActiveAssortmentIds().ToArray())
                Else
                    query.Add(" ) ")
                End If

 

If you have more than one assortment we have an exception as values should be handle like this:

String.Join(",", notActiveAssortments.ToArray())

Besides I think that you should escape the assortment ids.

 

I really hope this can be fixed quickly.

 

Best regards, Andesr


Replies

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply

Hi Anders,

You don't mention which exception you get, so it's difficult for me to guide you.

However, I can say something about the issues you bring up. The query is constructed using a CommandBuilder which is an API that we use to create parameterized queries when dealing with the database. It was made to make it easy to create SQL queries without opening injection attack vectors. Internally, the CommandBuilder turns the strings and given values into parameters before the query is executed. Specifically to your points, I do not believe that this causes an issue with multiple values nor do I believe that the values are passed unescaped. This can easily be tested by attaching a profiler to the database and executing the query or using debug=true in the frontend.

You're free to use the CommandBuilder in your custom projects as well. The API is public and all methods in the Database API support CommandBuilders as arguments.

If you have a concrete exception that is blocking you or if I have misunderstood your issue, pleas let me know and I will do what I can to help.

- Jeppe

 
Anders Ebdrup
Anders Ebdrup
Reply

Hi Jeppe,

 

This is the error: https://www.screencast.com/t/GzGxSgVIcVuS

Which occurs if you have more than one assortment in these two lines:

                    query.Add(" OR ( AssortmentItems.AssortmentItemAssortmentID IN ( {0} )  ", notActiveAssortments.ToArray())
                    query.Add(" AND AssortmentItems.AssortmentItemProductID NOT IN (SELECT AssortmentItemProductID FROM EcomAssortmentItems WHERE AssortmentItemAssortmentID IN ({0})) ) )", Services.Assortments.GetActiveAssortmentIds().ToArray())

 
Anders Ebdrup
Anders Ebdrup
Reply

Hi Jeppe,

 

You can also see the error in this statement. Take a look at "@p1", which is wrong, and you cannot execute the statement.  We really need a fix for this.


DECLARE @p0 NVARCHAR(8) = N'XPROTECT', @p1 NVARCHAR(20) = N'STANDARD','APPLIANCE', @p2 NVARCHAR(3) = N'ENU', @p3 BIT = 1, @p4 DATETIME = '2019-04-16 14:04:21.637', @p5 INT = 1, @p6 INT = 10
SELECT PagedProducts.GroupProductRelationSorting, PagedProducts.ProductSelectionTotalCount, ProductOutputs.*
FROM ( SELECT ProductResults.GroupProductRelationSorting, ProductResults.ProductAutoID, ProductResults.ProductSelectionTotalCount, ProductResults.RowNumber
FROM ( SELECT ProductSelections.GroupProductRelationSorting, EcomProducts.ProductAutoID, COUNT(EcomProducts.ProductID) OVER () AS ProductSelectionTotalCount, ROW_NUMBER() OVER(ORDER BY GroupProductRelationSorting ASC, ProductID ASC) AS RowNumber
FROM ( SELECT DISTINCT AssortedGroupProductSelections.GroupProductRelationProductID , AssortedGroupProductSelections.GroupProductRelationSorting
FROM ( SELECT DISTINCT GroupProductSelections.GroupProductRelationProductID , GroupProductSelections.GroupProductRelationSorting , AssortmentItems.AssortmentItemLanguageID
FROM ( SELECT EcomGroupProductRelation.GroupProductRelationProductID , MIN(EcomGroupProductRelation.GroupProductRelationSorting) AS GroupProductRelationSorting
FROM EcomGroupProductRelation
WHERE ( EcomGroupProductRelation.GroupProductRelationGroupID IN ( @p0 ) )
GROUP BY EcomGroupProductRelation.GroupProductRelationProductID ) AS GroupProductSelections
LEFT OUTER JOIN EcomAssortmentItems AS AssortmentItems ON ( AssortmentItems.AssortmentItemProductID = GroupProductSelections.GroupProductRelationProductID )
LEFT OUTER JOIN EcomAssortments AS Assortments ON ( Assortments.AssortmentID = AssortmentItems.AssortmentItemAssortmentID )
WHERE ( ( AssortmentItems.AssortmentItemAssortmentID IN ( @p1 ) )
OR ( AssortmentItems.AssortmentItemAssortmentID IS NULL )
OR ( ( COALESCE( AssortmentItems.AssortmentItemProductVariantID, '' ) <> '' )
AND (
NOT EXISTS(
SELECT MasterAssortmentItems.AssortmentItemAutoID
FROM EcomAssortmentItems AS MasterAssortmentItems
WHERE ( MasterAssortmentItems.AssortmentItemProductID = AssortmentItems.AssortmentItemProductID )
AND ( MasterAssortmentItems.AssortmentItemLanguageID = AssortmentItems.AssortmentItemLanguageID )
AND ( COALESCE( MasterAssortmentItems.AssortmentItemProductVariantID, '' ) = '' ) ) )
AND ( EXISTS( SELECT VariantProducts.ProductAutoID FROM EcomProducts AS VariantProducts
WHERE ( VariantProducts.ProductID = AssortmentItems.AssortmentItemProductID )
AND ( VariantProducts.ProductLanguageID = AssortmentItems.AssortmentItemLanguageID )
AND ( COALESCE( VariantProducts.ProductVariantID, '' ) <> '' )
AND (
NOT EXISTS ( SELECT VariantAssortmentItems.AssortmentItemProductVariantID
FROM EcomAssortmentItems AS VariantAssortmentItems
WHERE ( VariantAssortmentItems.AssortmentItemProductID = AssortmentItems.AssortmentItemProductID )
AND ( VariantAssortmentItems.AssortmentItemLanguageID = AssortmentItems.AssortmentItemLanguageID )
AND ( COALESCE( VariantAssortmentItems.AssortmentItemProductVariantID, '' ) = COALESCE( VariantProducts.ProductVariantID, '' ) ) ) ) ) ) ) ) ) AS AssortedGroupProductSelections ) AS ProductSelections
INNER JOIN EcomProducts ON ( EcomProducts.ProductID = ProductSelections.GroupProductRelationProductID )
AND ( EcomProducts.ProductLanguageID = @p2 )
AND ( EcomProducts.ProductActive = @p3 )
AND ( ( ISNULL( EcomProducts.ProductPeriodId, '' ) = '' )
OR ( EcomProducts.ProductPeriodId IN (
SELECT EcomPeriods.PeriodID
FROM EcomPeriods
WHERE ( ( COALESCE( EcomPeriods.PeriodShowProductsAfterExpiration, 0 ) = @p3 )
OR ( ( COALESCE( EcomPeriods.PeriodActive, 1 ) = @p3 )
AND ( ( COALESCE( EcomPeriods.PeriodAlways, 0 ) = @p3 )
OR ( ( COALESCE( EcomPeriods.PeriodEndDate, @p4 ) >= @p4 )
AND ( COALESCE( EcomPeriods.PeriodStartDate, @p4 ) <= @p4 ) ) ) ) )
AND ( EcomPeriods.PeriodHidden IN ( 1, @p3 ) ) ) ) )
AND ( COALESCE( EcomProducts.ProductVariantID, '' ) = '')
AND ( ISNULL(EcomProducts.ProductHidden, 0) <> @p3 ) ) AS ProductResults
WHERE ( ProductResults.RowNumber BETWEEN @p5 And @p6 ) ) As PagedProducts
INNER JOIN EcomProducts As ProductOutputs On ( ProductOutputs.ProductAutoID = PagedProducts.ProductAutoID )
ORDER BY PagedProducts.RowNumber ASC

 

Best regards, Anders

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply
This post has been marked as an answer

Hi Anders,

A couple of comments to your post.

First, I've reproduced the issue and I've implemented a fix. It has bug number 63665 and is currently awaiting QA testing. To elaborate a little on the issue, I can say that it's not caused by any SQL execution. As mentioned previously, we use a CommandBuilder class to create queries that parameterized queries. The Add function has an overload which accepts a formattable text and a param array with the values. The function then turns the placeholders and values into parameters. Because it accepts a param array, just like string.Format, and GetProductSql passes an array object as the first argument, the values in the array are expanded and this causes a mismatch between the number of placeholders and the number of values. This is the cause of the exception.

Second, the debug log doesn't show the query that is actually executed on the database, unfortunately. I've executed the same query on my solution and I've attached the query text as seen by the SQL Profiler. It is executable. Also, please note that this query isn't actually related to the original issue but traces back to GetPagedProductsByGroupIdsWithCount.

I hope this helps.

- Jeppe

exec sp_executesql N'SELECT PagedProducts.ProductSelectionTotalCount, ProductOutputs.* FROM ( SELECT ProductResults.ProductAutoID, ProductResults.ProductSelectionTotalCount, ProductResults.RowNumber FROM ( SELECT EcomProducts.ProductAutoID, COUNT(EcomProducts.ProductID) OVER () AS ProductSelectionTotalCount, ROW_NUMBER() OVER(ORDER BY ProductName COLLATE Latin1_General_CI_AS ASC, ProductID ASC) AS RowNumber FROM ( SELECT DISTINCT AssortedGroupProductSelections.GroupProductRelationProductID FROM ( SELECT DISTINCT GroupProductSelections.GroupProductRelationProductID , AssortmentItems.AssortmentItemLanguageID FROM ( SELECT EcomGroupProductRelation.GroupProductRelationProductID FROM EcomGroupProductRelation WHERE ( EcomGroupProductRelation.GroupProductRelationGroupID IN ( @p0 , @p1 , @p2 , @p3 , @p4 , @p5 ) ) GROUP BY EcomGroupProductRelation.GroupProductRelationProductID ) AS GroupProductSelections LEFT OUTER JOIN EcomAssortmentItems AS AssortmentItems ON ( AssortmentItems.AssortmentItemProductID = GroupProductSelections.GroupProductRelationProductID ) LEFT OUTER JOIN EcomAssortments AS Assortments ON ( Assortments.AssortmentID = AssortmentItems.AssortmentItemAssortmentID ) WHERE ( ( AssortmentItems.AssortmentItemAssortmentID IN ( @p6 ) ) OR ( AssortmentItems.AssortmentItemAssortmentID IS NULL ) OR ( ( COALESCE( AssortmentItems.AssortmentItemProductVariantID, '''' ) <> '''' ) AND ( NOT EXISTS( SELECT MasterAssortmentItems.AssortmentItemAutoID FROM EcomAssortmentItems AS MasterAssortmentItems WHERE ( MasterAssortmentItems.AssortmentItemProductID = AssortmentItems.AssortmentItemProductID ) AND ( MasterAssortmentItems.AssortmentItemLanguageID = AssortmentItems.AssortmentItemLanguageID ) AND ( COALESCE( MasterAssortmentItems.AssortmentItemProductVariantID, '''' ) = '''' ) ) ) AND ( EXISTS( SELECT VariantProducts.ProductAutoID FROM EcomProducts AS VariantProducts WHERE ( VariantProducts.ProductID = AssortmentItems.AssortmentItemProductID ) AND ( VariantProducts.ProductLanguageID = AssortmentItems.AssortmentItemLanguageID ) AND ( COALESCE( VariantProducts.ProductVariantID, '''' ) <> '''' ) AND ( NOT EXISTS ( SELECT VariantAssortmentItems.AssortmentItemProductVariantID FROM EcomAssortmentItems AS VariantAssortmentItems WHERE ( VariantAssortmentItems.AssortmentItemProductID = AssortmentItems.AssortmentItemProductID ) AND ( VariantAssortmentItems.AssortmentItemLanguageID = AssortmentItems.AssortmentItemLanguageID ) AND ( COALESCE( VariantAssortmentItems.AssortmentItemProductVariantID, '''' ) = COALESCE( VariantProducts.ProductVariantID, '''' ) ) ) ) ) ) ) ) ) AS AssortedGroupProductSelections ) AS ProductSelections INNER JOIN EcomProducts ON ( EcomProducts.ProductID = ProductSelections.GroupProductRelationProductID ) AND ( EcomProducts.ProductLanguageID = @p7 ) AND ( EcomProducts.ProductActive = @p8 ) AND ( ( ISNULL( EcomProducts.ProductPeriodId, '''' ) = '''' ) OR ( EcomProducts.ProductPeriodId IN ( SELECT EcomPeriods.PeriodID FROM EcomPeriods WHERE ( ( COALESCE( EcomPeriods.PeriodShowProductsAfterExpiration, 0 ) = @p8 ) OR ( ( COALESCE( EcomPeriods.PeriodActive, 1 ) = @p8 ) AND ( ( COALESCE( EcomPeriods.PeriodAlways, 0 ) = @p8 ) OR ( ( COALESCE( EcomPeriods.PeriodEndDate, @p9 ) >= @p9 ) AND ( COALESCE( EcomPeriods.PeriodStartDate, @p9 ) <= @p9 ) ) ) ) ) AND ( EcomPeriods.PeriodHidden IN ( 1, @p8 ) ) ) ) ) AND ( COALESCE( EcomProducts.ProductVariantID, '''' ) = '''') AND ( ISNULL(EcomProducts.ProductHidden, 0) <> @p8 ) ) AS ProductResults WHERE ( ProductResults.RowNumber BETWEEN @p10 And @p11 ) ) As PagedProducts INNER JOIN EcomProducts As ProductOutputs On ( ProductOutputs.ProductAutoID = PagedProducts.ProductAutoID ) ORDER BY PagedProducts.RowNumber ASC',N'@p0 nvarchar(6),@p1 nvarchar(6),@p2 nvarchar(6),@p3 nvarchar(7),@p4 nvarchar(7),@p5 nvarchar(8),@p6 nvarchar(25),@p7 nvarchar(5),@p8 bit,@p9 datetime,@p10 int,@p11 int',@p0=N'GROUP5',@p1=N'GROUP7',@p2=N'GROUP8',@p3=N'GROUP27',@p4=N'GROUP65',@p5=N'GROUP123',@p6=N'ASSORTMENT1'',''ASSORTMENT2',@p7=N'LANG1',@p8=1,@p9='2019-04-16 16:58:29.180',@p10=1,@p11=10

Votes for this answer: 1
 
Anders Ebdrup
Anders Ebdrup
Reply

Yes, we have two bugs with sql and assortments, so hopefully you will fix both of them? :-)

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply

I can only reproduce the bug with GetProductSql, which has been fixed. You can download Dynamicweb.Ecommerce 1.6.24 from NuGet which contains the fix. A hotfix for 9.6 will follow, probably next week depending on Easter.

With regard to the second bug, you mention. I've been unable to reproduce any bug related to the SQL that we've been posting here. If you have a solution that fails with this query, please send it so me so I can investigate. Based on the information in the thread, I cannot pinpoint the issue.

If you mean that the second bug is how the debug log represents the query then that is probably not something we'll make a hotfix for. I've added it to our backlog to be fixed at a later time.

- Jeppe

 
Jeppe Eriksson Agger Dynamicweb Employee
Jeppe Eriksson Agger
Reply

Hi Anders,

Dynamicweb.Ecommerce 1.6.25 is now ready for download on NuGet.

- Jeppe

 
Kristian Kirkholt Dynamicweb Employee
Kristian Kirkholt
Reply
This post has been marked as an answer

Hi Anders

The problem TFS#63685 "Products might not be shown correctly if user is part of multiple assortments" has now been fixed in Package "Dynamicweb.Ecommerce" version 1.6.25

You are able to find this update in the backend Package update section.

Also the correction are part of the 9.6.7 hotfix release 

You are able to find this build in the download section:

http://doc.dynamicweb.com/releases-and-downloads/releases

Please contact Dynamicweb Support if you need any additional help regarding this.

Kind Regards
Dynamicweb Support
Kristian Kirkholt

Votes for this answer: 1

 

You must be logged in to post in the forum