我輩はブロガーではない。ネタもまだない

SASとかDelphiあたりの人様の役に立たないネタを提供します

CDATA SAS.dsを使ってみる(その1:データセットアクセス編)

すでにまとめ記事を上げていますがそれぞれ細かく掘り下げていきます。

Delphiでアプリケーションの作成手順


CDATA Firedac components for SASdatasets はβ版 21.0.7829 を使用しました。
CDATAのドキュメントではVCLとなっていますが、FMXでも動くっぽいです。想定外なのかもしれませんが。

新規アプリケーション作成で開いたフォームに以下を貼り付けます。
TFDPhysCDataSASDataSetsDriverLink
TFDConnection
TFDQuery
TFDGUIxWaitCursor
TFDMetaInfoQuery

さらにデータを表示するためにVCLならTDBGridとTDatasource、FMXならTStringGridを貼り付けます。
(TDBGridの方が圧倒的に楽ちんですが、将来的な見栄えいいアプリケーションを作りたいならFMX、かな?)

また、ライブラリ内のデータセットを選択するため、TComboboxも貼り付けます
なお、この記事では、ライブラリを「C:\Temp」に固定し、フレームワークFMXを選択しています。

続いて、フォーム生成時のソースです。
ここでは、指定フォルダ内のデータセットを列挙し、コンボボックスに格納します。

begin
  FDConnection1.Params.Add('URI=C:\Temp');
  combobox1.Items.Clear;
  combobox1.Items.Add('');
  FDMetaInfoQuery1.Connection := FDConnection1;
  FDMetaInfoQuery1.MetaInfoKind := mkTables;
  FDMetaInfoQuery1.Open;
  while(not(FDMetaInfoQuery1.Eof))do begin
    combobox1.Items.Add(FDMetaInfoQuery1.FieldByName('TABLE_NAME').AsString);
    FDMetaInfoQuery1.Next;
  end;
  FDMetaInfoQuery1.Close;
end;


以下のコードでデータセットにアクセスします。
(ボタンのOnClick等に割り当て)

var
  i,cnt:integer;
  reccnt,fldcnt:integer;
begin
  cnt:=StringGrid1.ColumnCount;
  for i:=cnt-1 downto 0 do begin
    StringGrid1.Columns[i].Free;
  end;

  fdquery1.Close;
  fdquery1.SQL.Text:='select count(*) as cnt from '+combobox1.Items[combobox1.ItemIndex]+';';
  fdquery1.Open();
  reccnt:=fdquery1.FieldByName('cnt').AsInteger;
  StringGrid1.RowCount:=reccnt;
  fdquery1.Close;

  fdquery1.SQL.Text:='select * from '+combobox1.Items[combobox1.ItemIndex]+';';
  fdquery1.Open();
  fldcnt:=fdquery1.FieldCount;

  StringGrid1.AddObject(TStringColumn.Create(StringGrid1));
  StringGrid1.Columns[0].Header := 'No.';
  for i:=1 to fldcnt do begin
    StringGrid1.AddObject(TStringColumn.Create(StringGrid1));
    StringGrid1.Columns[i].Header := fdquery1.FieldDefs[i-1].Name;
  end;

  cnt:=0;
  while(not(fdquery1.Eof)) do begin
    StringGrid1.Cells[0,cnt]:=(cnt+1).ToString;
    for i:=0 to fldcnt-1 do begin
      StringGrid1.Cells[i+1,cnt]:=fdquery1.Fields[i].AsString;
    end;
    inc(cnt);
    fdquery1.Next;
  end;
  fdquery1.Close;

end;

上記のアプリケーションを作成した後は、検証するSASデータセットを以下のコードを実行して生成します。

libname temp 'c:\temp';
/* サンプルデータ */
data temp.test;
  length char $5;
  do i=1 to 50;
    char=' '||byte(64+i)||' ';
    output;
  end;
run;
/* PWでパスワードを指定 */
data temp.pw(pw=abc);
  set temp.test(firstobs=2);
run;
/* READ、WRITE、ALTERパスワードを別々に指定 */
data temp.rwa(read=a write=b alter=c);
  set temp.test(firstobs=4);
run;

それぞれのデータセットにアクセスしてみましょう。

パスワード付きデータセットはパスワードが無視される

これ、ホント危険です。パスワードが意味をなさないのですから。

f:id:japelin:20210614161113p:plain
検証のベースとなるデータセット
f:id:japelin:20210614162347p:plain
PWを指定したはずのデータセットにパスワードなしでアクセスできる
f:id:japelin:20210614162401p:plain
READ,WRITE,ALTERを別々に指定したはずのデータセットにパスワードなしでアクセスできる

暗号化データセットにはアクセスできない

/* パスワード+暗号化 */
data temp.enc(pw=abc encrypt=yes);
  set temp.test(firstobs=6);
run;
f:id:japelin:20210614163607p:plain
暗号化データセットにはアクセスできない

やっぱり、パスワードだけじゃなく、暗号化は必須ですね。(互換性、接続性はおいておいて)

圧縮データセットにアクセスできない

文字が多くてサイズが大きいデータセットに有効なんですが、勿体ないですねぇ。

/* 圧縮 */
data temp.cmp(compress=yes);
  set temp.test(firstobs=7);
run;
f:id:japelin:20210614165502p:plain
エラー等は出ないが、正しくデータが取得できない


特殊なことをしている場合は、アクセスできないかもしれないです。
あと、パスワード回避については早々に修正していただきたいですね。
(パスワード忘れて困ってる方がいらっしゃったら声をかけてくださいw)