Показать сообщение отдельно
Старый 25.04.2007, 13:49   #1  
EVGL is offline
EVGL
Banned
Соотечественники
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
 
4,445 / 3001 (0) ++++++++++
Регистрация: 09.07.2002
Адрес: Parndorf, AT
Интеграция с Reporting Services в 4.0, ужасы SysSRSTablePermissions
Хотел бы поделиться изысканиями с коллегами.

После часов настройки MS SQL 2005 Reporting Services я сумел сделать в Report Builder простенький отчет матричного вида, показывающий, сколько времени отработали рабочие в разбивке по станкам. Для отчета была сформирована модель SMDL с таблицей ProdRouteTrans из перспективы Production.

Запустив полученный отчет, я был неприятно раздосадован тем, что в нем стояли одни нули, хотя проводки в БД были на месте. Возникло подозрение, что модель SMDL использует не таблицы, а ссылается на какие-то специальные view. Кроме того, я сделал наблюдение, что модели экспортируются из DAX все за раз без учета компаний. Сам SMDL - это здоровенный файл XML, для которого я не нашел графического редактора. Тем не менее, фильтр по компании в SMDL определенно отсутствовал.

Запустив SQL Server Profiler, я выделил собственно запрос, который идет к базе данных (извините за немецкие имена, модель SMDL была экспортирована с языком de-at):
X++:
SET DATEFIRST 1
SELECT
    CAST(1 AS BIT) [c0_is_agg],
    CAST(1 AS BIT) [c1_is_agg],
    CAST(2 AS INT) [agg_row_count],
    [PRODROUTETRANSWITHUSERIDS].[SummeGutmenge_Sum] [SummeGutmenge_Sum],
    [PRODROUTETRANSWITHUSERIDS].[SummeStunden_Sum] [SummeStunden_Sum],
    [PRODROUTETRANSWITHUSERIDS].[Mitarbeiter] [Mitarbeiter],
    [PRODROUTETRANSWITHUSERIDS].[Ressource] [Ressource]
FROM
    (
        SELECT
            SUM([PRODROUTETRANSWITHUSERIDS].[QTYGOOD]) [SummeGutmenge_Sum],
            SUM([PRODROUTETRANSWITHUSERIDS].[HOURS]) [SummeStunden_Sum],
            [PRODROUTETRANSWITHUSERIDS].[EMPLID] [Mitarbeiter],
            [PRODROUTETRANSWITHUSERIDS].[WRKCTRID] [Ressource]
        FROM
            [DBO].[PRODROUTETRANSWITHUSERIDS] [PRODROUTETRANSWITHUSERIDS]
        WHERE
            [PRODROUTETRANSWITHUSERIDS].[WindowsID] = 'MF\evggla'
        GROUP BY
            [PRODROUTETRANSWITHUSERIDS].[EMPLID], [PRODROUTETRANSWITHUSERIDS].[WRKCTRID]
    ) [PRODROUTETRANSWITHUSERIDS]
ORDER BY
    [Mitarbeiter], [Ressource]
Из этого запроса видно: (1) обращение идет не к таблице ProdRouteTrans, а к представалению PRODROUTETRANSWITHUSERIDS; (2) нет фильтра по компании; (3) есть фильтр по пользователю Windows

Определение самого представления, автоматически сформированного Аксаптой в момент экспорта моделей, вызывает ужас:

X++:
SELECT     FINALLIST.WINDOWSID, dbo.PRODROUTETRANS.DATAAREAID, dbo.PRODROUTETRANS.RECVERSION, dbo.PRODROUTETRANS.RECID, 
                      CASE WHEN DBO.FIELDVISIBLE(FIELDMASKSTRING, 1) > 0 THEN PRODID ELSE NULL END AS PRODID, 
                      CASE WHEN DBO.FIELDVISIBLE(FIELDMASKSTRING, 2) > 0 THEN OPRNUM ELSE NULL END AS OPRNUM, 
                      CASE WHEN DBO.FIELDVISIBLE(FIELDMASKSTRING, 3) > 0 THEN JOBID ELSE NULL END AS JOBID, 
                      CASE WHEN DBO.FIELDVISIBLE(FIELDMASKSTRING, 4) > 0 THEN JOBTYPE ELSE NULL END AS JOBTYPE, 
 ...
FROM         (SELECT DISTINCT 
                                              USERDOMAINLIST.WINDOWSID, VIRTUALDOMAINLIST.COMPANY_ID, dbo.FIELDMASK(261, USERDOMAINLIST.USERINFO_USERID, 
                                              VIRTUALDOMAINLIST.COMPANY_ID) AS FIELDMASKSTRING, USERDOMAINLIST.USERINFO_USERID
                       FROM          (SELECT     dbo.VIRTUALDATAAREALIST.VIRTUALDATAAREA AS COMPANY_ID, dbo.COMPANYDOMAINLIST.DOMAINID
                                               FROM          dbo.VIRTUALDATAAREALIST INNER JOIN
                                                                      dbo.COMPANYDOMAINLIST ON dbo.COMPANYDOMAINLIST.COMPANYID = dbo.VIRTUALDATAAREALIST.ID
                                               WHERE      (dbo.VIRTUALDATAAREALIST.VIRTUALDATAAREA IN
                                                                          (SELECT     DATAAREAID
                                                                            FROM          dbo.PRODROUTETRANS))
                                               UNION
                                               SELECT     COMPANYID AS COMPANY_ID, DOMAINID
                                               FROM         dbo.COMPANYDOMAINLIST
                                               WHERE     (COMPANYID IN
                                                                         (SELECT     DATAAREAID
                                                                           FROM          dbo.PRODROUTETRANS))) AS VIRTUALDOMAINLIST INNER JOIN
                                                  (SELECT DISTINCT 
                                                                           dbo.WINDOWSID(dbo.USERINFO.NETWORKDOMAIN, dbo.USERINFO.NETWORKALIAS) AS WINDOWSID, TPERMS.DOMAINID, 
                                                                           dbo.USERGROUPLIST.GROUPID, dbo.USERINFO.ID AS USERINFO_USERID
                                                    FROM          dbo.USERGROUPLIST INNER JOIN
                                                                           dbo.USERINFO ON dbo.USERINFO.ID = dbo.USERGROUPLIST.USERID AND dbo.USERINFO.ENABLE = 1 INNER JOIN
                                                                               (SELECT     DOMAINID, GROUPID
                                                                                 FROM          dbo.SYSSRSTABLEPERMISSIONS AS A
                                                                                 WHERE      (TABID = 261)) AS TPERMS ON dbo.USERGROUPLIST.GROUPID = TPERMS.GROUPID OR 
                                                                           dbo.USERGROUPLIST.GROUPID = 'ADMIN') AS USERDOMAINLIST ON 
                                              USERDOMAINLIST.DOMAINID = VIRTUALDOMAINLIST.DOMAINID OR VIRTUALDOMAINLIST.DOMAINID = 'ADMIN' AND 
                                              USERDOMAINLIST.GROUPID = 'ADMIN') AS FINALLIST INNER JOIN
                      dbo.PRODROUTETRANS ON dbo.PRODROUTETRANS.DATAAREAID = FINALLIST.COMPANY_ID
Ключевая таблица здесь - это SYSSRSTABLEPERMISSIONS, которая была пустой! Неудивительно, что запрос не возвращал данных.

Системная для Аксапта таблица SYSSRSTABLEPERMISSIONS содержит представление всех прав доступа к полям и таблицам в Аксапта в разрезе доменов и групп. При этом таблица строится в методе Classes\xAccessRightsList\saveSecurityRights при принудительном задании прав доступа. Поскольку мой пользователь "MF\evggla" принадлежал только группе Admin, для этой группы в таблице записей не было.

После того, как я создал новую группу пользователей Test, Аксапта заполнила таблицу:
Нажмите на изображение для увеличения
Название: SysSRS.GIF
Просмотров: 387
Размер:	15.7 Кб
ID:	2587

Представление PRODROUTETRANSWITHUSERIDS стало возвращать данные:
Нажмите на изображение для увеличения
Название: ViewProdRouteTrans.GIF
Просмотров: 401
Размер:	21.5 Кб
ID:	2589

Отчет выдал результаты... просуммированные по всем компаниям в базе.

Выводы:
  1. DAX пытается вынудить Reporting Services учитывать собственные права доступа
  2. Если пользователь принадлежит только группе Admin, он не видит ничего
  3. Если вы создали новое поле, то данные не будут показаны даже при условии, что модели SMDL экспортированы заново, поскольку таблица SYSSRSTABLEPERMISSIONS не обновлена
  4. Если пользователь имеет права на домен, в который входит несколько компаний, отчеты показывают по умолчанию суммы по всем компаниям
  5. Если это так, то предотвратить это можно фильтром по компании в самом отчете
  6. Становится более понятно, почему пользователи DAX обязательно должны соответствовать пользователям Windows
  7. Reporting Services - это еще один способ обойти RLS

Последний раз редактировалось EVGL; 25.04.2007 в 14:01.
За это сообщение автора поблагодарили: belugin (9), Logger (5), gl00mie (4), driller (1).