飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 1547|回复: 0

mdb Utils (Access)

[复制链接]
  • TA的每日心情
    开心
    2019-9-19 16:05
  • 签到天数: 4 天

    [LV.2]偶尔看看I

    发表于 2007-2-8 10:27:07 | 显示全部楼层 |阅读模式
    unit mdbUtils;

    interface
    uses windows,classes,sysutils,dao2000,dao97, comobj,adodb{$ifdef ver140},variants{$endif},dialogs;

    type
      TFieldRec=record
        fieldname:string;
        fieldType,fieldSize:integer;
        Required:boolean;
        DefaultValue:olevariant;
        ForeignName:string;
      end;
      TFieldRecArray=Array of TFieldRec;

      TrelationRec=record
        name,table,foreignTable:string;
        Attributes:integer;
        fields:TfieldRecArray;
      end;
      TRelationArray=array of TrelationRec;


      TindexRec=record
        name:string;
        primary,unique,Required:boolean;
        fields:TfieldRecArray;
      end;
      TIndexRecArray=array of TIndexRec;


      TParamRec=record
        value :olevariant;
        type_:smallint;
        Direction:smallint;
        name : widestring;
      end;
      TparamRecArray=array of TparamRec;

      TqueryDef=record
        name:string;
        sql:string;
      end;
      TqueryDefArray=array of TqueryDef;


    function GetWinTempFile:string;
    procedure CompactMdbDatabase(srcDbname,dstDbname,oldpwd,newpwd:string;bAccess97:boolean=true);
    procedure CompactMdbDatabaseX(Dbname:string);
    procedure changeMdbPwd(dbname,oldpwd,newpwd:string;bAccess97:boolean=true);
    procedure clearLinkTables(dbname,pwd:string);
    procedure connectx(srcName, srcPwd, dstName, dstPwd,suffix: String);
    function GetMDBPassWord(filename:string):string;
    function ConnectAdo(adoconnection:TadoConnection;dbName,pwd:string):boolean;
    function CreateMdb(dbname,pwd:string):boolean;
    function isAccess97(dbname:string):boolean;
    function OpenDatabase(dbname,pwd:string):database;
    //relations
    function GetRelations(dbname,pwd:string):TrelationArray;
    procedure ClearRelations(dbname,pwd:string);
    procedure CreateRelations(dbname,pwd:string;rs:TrelationArray);
    //recordset
    function createMDBTable(db:database;tbname:string;fldArray:TFieldRecArray;IdxArray:TIndexRecArray):tableDef;
    procedure AlterMdbTable(db:database;tbname:string;fldArray:TfieldRecArray;IdxArray:TindexRecArray);
    //function compareMdbTable(srcdb,dstdb:database;tbname:string;var outstr:string):boolean;
    procedure renameMDBtable(db:database;srctbname,dstTbname:string);
    procedure copyMdbTable(db:database;srcTdf,dstTdf:TableDef);
    procedure dropmdbTable(db:database;tbname:string);

    //querydefs
    function getQuerydefs(dbname,pwd:string):TquerydefArray;
    function clearQuerydefs(db:database):boolean;
    function createQueryDef(db:database;qdf:TqueryDef):queryDef;
    function createQueryDefs(db:database;qa:TquerydefArray):boolean;
    implementation

    function createQueryDefs(db:database;qa:TquerydefArray):boolean;
    var i:integer;
    begin
      result := false;
      for i:=0 to high(qa) do
      begin
        db.createQueryDef(qa.name,qa.sql);
      end;
      result := true;
    end;
    function createQueryDef(db:database;qdf:TqueryDef):queryDef;
    var i:integer;
    begin
      result := nil;
      result := db.CreateQueryDef(qdf.name,qdf.sql);
    end;

    function clearQuerydefs(db:database):boolean;
    var i:integer;
    begin
      for i:= db.QueryDefs.count -1 downto 0 do
      begin
        db.querydefs.Delete(db.querydefs.Name);
      end;
      db.QueryDefs.Refresh;
    end;


    function getQuerydefs(dbname,pwd:string):TquerydefArray;
    var db:database;
        i,j:integer;
    begin
      db := opendatabase(dbname,pwd);
      setlength(result,db.querydefs.count);
      for i:=0 to db.QueryDefs.count-1 do
      begin
        result.name := db.QueryDefs.Name;
        result.sql := db.QueryDefs.sql;
      end;
    end;

    procedure dropmdbTable(db:database;tbname:string);
    begin
      db.TableDefs.Delete(tbname);
      db.TableDefs.Refresh;
    end;

    procedure copyMdbTable(db:database;srcTdf,dstTdf:TableDef);
    const
      sqlstr='insert into %s select %s from %s';
    var s:string;
        i:integer;
    begin
      s := '';
      for i:=0 to dstTdf.Fields.Count -1 do
      begin
        try
        if assigned(srcTdf.fields[dstTdf.fields.name]) then
        begin
          if s<>'' then s := s +',';
          s := s +dstTdf.fields.Name;
        end;
        except
        end;
      end;
      if s<>'' then
        db.Execute(format(sqlstr,[dsttdf.name,s,srctdf.name]),DbSQLPassThrough);
    end;

    procedure renameMDbtable(db:database;srctbname,dstTbname:string);
    var tdf:tabledef;
    begin
      tdf := db.TableDefs[srctbname];
      if assigned(tdf) then
      begin
        tdf.Set_Name(dstTbname);
        db.TableDefs.Refresh;
      end;
    end;

    procedure AlterMdbTable(db:database;tbname:string;fldArray:TfieldRecArray;IdxArray:TindexRecArray);
    var
      tdfold,tdfnew:tabledef;
      fld:field;
      idx  : _index;
      i ,j : integer;
      bfound:boolean;
    begin
      tdfold := db.TableDefs[tbname];
      if not assigned(tdfold) then exit;
      tdfnew := createmdbTable(db,'temp2002xh',fldArray,idxArray);
      copymdbTable(db,tdfold,tdfnew);
      dropmdbTable(db,tbname);
      renameMdbTable(db,'temp2002xh',tbname);
    end;

    function createMDBTable(db:database;tbname:string;fldArray:TFieldRecArray;IdxArray:TIndexRecArray):tableDef;
    var
      tb   : tabledef;
      fld  : field;
      idx  : _index;
      i ,j : integer;
    begin
      tb := db.CreateTableDef(tbname,0,'','');
      for i:=0 to high(fldArray) do
      begin
        fld := tb.CreateField(fldarray.fieldname,fldarray.fieldType,fldArray.fieldSize);
        fld.Set_Required(fldArray.Required);
        fld.Set_DefaultValue(fldArray.DefaultValue);
        tb.Fields.Append(fld);
      end;
      for i:=0 to high(idxArray) do
      begin
        idx := tb.CreateIndex(idxArray.name);
        idx.Set_Primary(idxArray.primary );
        idx.Set_Unique(idxArray.unique);
        idx.Set_Required(idxArray.Required);
        for j:=0 to high(idxArray.fields) do
        begin
          fld := idx.CreateField(idxArray.fields[j].fieldname,idxArray.fields[j].fieldType,idxArray.fields[j].fieldSize);
          idx.Fields.append(fld);
        end;
        tb.Indexes.Append(idx);
      end;
      db.TableDefs.Append(tb);
      result := tb;
    end;

    procedure CompactMdbDatabaseX(Dbname:string);
    var pwd:string;
        tmpdb:string;
    begin
      pwd := getMdbPassword(dbname);
      tmpdb := getWinTempfile;
      tmpDb := changefileExt(tmpdb,'.mdb');
      compactMdbDatabase(dbname,tmpdb,pwd,'',isAccess97(dbname));
      if fileExists(tmpdb) then
      begin
        copyfile(pchar(tmpdb),pchar(dbname),false);
        deletefile(tmpdb);
      end;
    end;

    procedure CreateRelations(dbname,pwd:string;rs:TrelationArray);
    var db:database;
        i,j : integer;
        fld:field;
        r:relation;
    begin
      db := opendatabase(dbname,pwd);
      for i:= 0 to high(rs) do
      begin
        r :=  db.CreateRelation(rs.name,rs.table,rs.foreignTable,rs.Attributes);
        for j:= 0 to high(rs.fields) do
        begin
          fld := r.CreateField(rs.fields[j].fieldname,rs.fields[j].fieldType,rs.fields[j].fieldSize);
          fld.Set_ForeignName(rs.fields[j].foreignName);
          r.Fields.Append(fld);
        end;
        db.Relations.Append(r);
      end;
    end;

    function OpenDatabase(dbname,pwd:string):database;
    var db:database;
        dbEngine:_dbengine;
    begin
      if pwd <>'' then
        pwd := ';pwd='+pwd;
      if isAccess97(dbname) then
      begin
        dbengine := CreateComObject(dao97.CLASS_DBEngine) as _DBEngine;
        db := dbengine.OpenDatabase(dbname,dbDriverNoPrompt,false,pwd);
      end else
      begin
        dbengine := CreateComObject(dao2000.CLASS_DBEngine) as _DBEngine;
        db := dbengine.OpenDatabase(dbname,dbDriverNoPrompt,false,pwd)
      end;
      result :=  db;
    end;

    function GetRelations(dbname,pwd:string):TrelationArray;
    var db:database;
        i,j:integer;
        r:relation;
        tdf:tabledef;
        fn:string;
        fld:field;
    begin
      db := opendatabase(dbname,pwd);
      setlength(result,db.Relations.Count);
      for i:=0 to db.Relations.Count -1 do
      begin
        r :=db.Relations;
        result.name := r.name;
        result.table := r.table;
        tdf := db.TableDefs[r.table];
        result.foreignTable := r.ForeignTable;
        result.Attributes := r.Attributes;
        setlength(result.fields,r.Fields.Count);
        for j:=0 to r.fields.Count -1 do
        begin
          result.Fields[j].fieldname := r.fields[j].Name;
          fn := r.fields[j].Name;
          fld := tdf.Fields[fn];
          result.fields[j].fieldSize := fld.Size;
          result.fields[j].fieldType := fld.Type_;
          try
          result.fields[j].foreignName := r.fields[j].ForeignName;
          except
            showmessage('error');
          end;
        end;
      end;
    end;

    function isAccess97(dbname:string):boolean;
    var fi:file of byte;
        i:integer;
        by:byte;
    begin
      AssignFile(FI,dbname);
      Reset(FI);
      result := false;
      // Read file
      I := 0;
      Repeat
        If not Eof(FI) then
        Begin
          Read(FI,By);
          Inc(I);
          if I=$15 then
          begin
            result := by<>1;
            break;
          end;
        End;
      Until  Eof(FI);
      closefile(fi);
    end;
    procedure ClearRelations(dbname,pwd:string);
    var db:database;
        dbEngine:_dbengine;
        tempname:string;
        i:integer;
    begin
      if pwd <>'' then
        pwd := ';pwd='+pwd;
      if isAccess97(dbname) then
      begin
        dbengine := CreateComObject(dao97.CLASS_DBEngine) as _DBEngine;
        db := dbengine.OpenDatabase(dbname,dbDriverNoPrompt,false,pwd);
      end else
      begin
        dbengine := CreateComObject(dao2000.CLASS_DBEngine) as _DBEngine;
        db := dbengine.OpenDatabase(dbname,dbDriverNoPrompt,false,pwd)
      end;
      for i:=db.Relations.Count -1 downto 0 do
        db.Relations.Delete(db.Relations.Item.Name);
    end;

    function CreateMdb(dbname,pwd:string):boolean;
    var dbengine:_dbEngine;
    begin
      result := true;
      try
      dbengine := CreateComObject(CLASS_DBEngine) as _DBEngine;
      dbengine.CreateDatabase(dbname,';pwd='+pwd,dbVersion30);
      except
        result := false;
      end;
    end;

    function ConnectAdo(adoconnection:TadoConnection;dbName,pwd:string):boolean;
    var s:string;
    begin
      result := false;
      s:='Provider=Microsoft.Jet.OLEDB.4.0;';
      s:=s+'User ID=Admin;';
      s:=s+'Data Source='+dbName+';';
      s:=s+'Mode=Share Deny None;';
      s:=s+'Jet OLEDB:Database Password="'+pwd+'";';
      try
      adoconnection.connected := false;
      adoconnection.connectionstring := s;
      adoconnection.connected := true;
      except
      end;
      result := adoConnection.connected;
    end;

    function GetMDBPassWord(filename:string):string;
    Const
       XorArr97 : Array[0..12] of Byte =
       ($86,$FB,$EC,$37,$5D,$44,$9C,$FA,$C6,$5E,$28,$E6,$13);
       xorArr2000: Array[0..28] of Byte =
       ($A2,$69,$EC,$37,$79,$D6,$9C,$FA,$E2,$CC,$28,$E6,$37,$24,$8A,$60,$70,$06,$7B,$36,$D1,$E0,$DF,$B1,$53,$66,$13,$43,$EB);
    Var
       I                : Integer;
       S1               : String;
       FI               : File of Byte;
       By               : Byte;
       Access97         : Boolean;
       FileError        : Boolean;
       count            : integer;
    Begin
      result := '';
      // Init
      FileError := False;
      Access97 := True;
      // Open *.mbd file
      AssignFile(FI,Filename);
      Reset(FI);
      // Read file
      I := 0;
      Repeat
        If not Eof(FI) then
        Begin
          Read(FI,By);
          Inc(I);
          if I=$15 then
            access97 := by<>1;
        End;
      Until (I = $42) or Eof(FI);
      If Eof(FI) then
        raise exception.create('无效的数据库文件');
      // Read password string
      S1 := '';
      if Access97 then count := 12
      else count := 28;
      For I := 0 to count do
      If not Eof(FI) then
      Begin
        Read(FI,By);
        S1 := S1 + Chr(By);
      End;
      If Eof(FI) then
        raise exception.create('无效的数据库文件');
      //Close file
      CloseFile(FI);
      // Decode string
      For I := 0 to count do
         if access97 then
         S1[I + 1] := Chr(Ord(S1[I + 1]) xor XORArr97[I])
         else
         S1[I + 1] := Chr(Ord(S1[I + 1]) xor XORArr2000[I]);
      If Access97 then
         result := s1
      else
      begin
        result := '';
        for i:=0 to length(s1) div 2 do
        begin
          result := result +widechar(ord(s1[i*2+1])+ord(s1[i*2+2])shl 8);
        end;
      end;
    End;

    //note: srcdbname and dstdbname cann't be the same
    procedure CompactMdbDatabase(srcDbname,dstDbname,oldpwd,newpwd:string;bAccess97:boolean=true);
    var idbEngine:_dbEngine;
    begin
      if oldpwd <>'' then oldpwd := ';pwd='+oldpwd;
      if newpwd <>'' then newpwd := ';pwd='+newpwd;

      if bAccess97 then
      begin
        idbengine := CreateComObject(dao97.CLASS_DBEngine) as _DBEngine;
        idbEngine.CompactDatabase(srcDbname,dstDbname,newpwd,dbVersion30,oldpwd);
      end else
      begin
        idbengine := CreateComObject(dao2000.CLASS_DBEngine) as _DBEngine;
        idbEngine.CompactDatabase(srcDbname,dstDbname,newpwd,dbVersion40,oldpwd);
      end;
    end;

    function GetWinTempFile:string;
    var fn,pn:array[0..MAX_Path-1]of char;
    begin
      getTempPath(MAX_PATH,pn);
      gettempfilename(pn,'TEMP',999,fn);
      result := fn;
    end;
    //note try to clear access2000 database's pwd may raise an error
    procedure changeMdbPwd(dbname,oldpwd,newpwd:string;bAccess97:boolean=true);
    var db:database;
        dbEngine:_dbengine;
        tempname:string;
    begin
      if bAccess97 then
      begin
        dbengine := CreateComObject(dao97.CLASS_DBEngine) as _DBEngine;
        db := dbengine.OpenDatabase(dbname,dbDriverNoPrompt,false,';pwd='+oldpwd);
        db.NewPassword(oldpwd,widestring(newpwd));
        db.Close;
      end else
      begin
        if (newpwd<>'') and (oldpwd <>'')then
        begin
          dbengine := CreateComObject(dao2000.CLASS_DBEngine) as _DBEngine;
          if oldpwd <>'' then
            db := dbengine.OpenDatabase(dbname,dbDriverNoPrompt,false,';pwd='+oldpwd)
          else
            db := dbengine.OpenDatabase(dbname,dbDriverNoPrompt,false,'');
          db.NewPassword(oldpwd,widestring(newpwd));
          db.Close;
        end else
        begin
          tempname := changefileext(getwintempfile,'.mdb');
          compactmdbDatabase(dbname,tempname,oldpwd,newpwd,false);
          copyfile(pchar(tempname),pchar(dbname),false);
          deletefile(tempname);
        end;
      end;
    end;

    procedure clearLinkTables(dbname,pwd:string);
    var engine : _dbengine;
        dbs:database;
        i:Integer;
        tdtest,tdfloop:TableDef;
        strtb,strConnect :string;
        tdfLinked:tableDef;
    begin
      engine := createcomobject(CLASS_DBEngine) as _dbengine;
      dbs := engine.OpenDatabase(dbname,dbDriverNoPrompt,false,';name=dbs;pwd='+pwd);

      for i := dbs.TableDefs.Count-1 downto 0 do
      begin
        tdfloop := dbs.TableDefs.Item;
          If ((tdfloop.Attributes And dbAttachedTable) <> 0) Or
                ((tdfloop.Attributes And dbAttachExclusive) <> 0) Or
                ((tdfloop.Attributes And dbAttachSavePWD) <> 0) Then
            dbs.TableDefs.Delete(tdfloop.Name)
      end;
    end;

    //link tables between databases
    procedure connectx(srcName, srcPwd, dstName, dstPwd,suffix: String);
    var engine : _dbengine;
        dbsSrc, dbsDst:database;
        i,j:Integer;
        tdtest,tdfloop:TableDef;
        strtb,strConnect :string;
        tdfLinked:tableDef;
    begin
      engine := createcomobject(CLASS_DBEngine) as _dbengine;
      dbssrc := engine.OpenDatabase(srcname,dbDriverNoPrompt,false,';name=dbsrc;pwd='+srcpwd);
      dbsDst := engine.OpenDatabase(dstname,dbDriverNoPrompt,false,';name=dbdst;pwd='+dstpwd);
      for i := dbsDst.TableDefs.Count-1 downto 0 do
      begin
        tdfloop := dbsDst.TableDefs.Item;
        If ((tdfloop.Attributes And dbAttachedTable) <> 0) Or
              ((tdfloop.Attributes And dbAttachExclusive) <> 0) Or
              ((tdfloop.Attributes And dbAttachSavePWD) <> 0) Then
          dbsDst.TableDefs.Delete(tdfloop.Name)
      end;

      for i:=0 to dbsSrc.TableDefs.count-1 do
      begin
        tdfloop := dbsSrc.tabledefs;
        If (tdfloop.Attributes And dbSystemObject) = 0 Then
        begin
          strtb := tdfloop.Name;
          for j:=0 to dbsDst.tabledefs.count-1 do
          begin
            tdTest := dbsDst.tableDefs.item[j];
            If tdTest.Name = strtb Then
            begin
              If Not (
               ((tdTest.Attributes and dbAttachedTable) <> 0) Or
               ((tdTest.Attributes And dbAttachExclusive) <> 0) Or
               ((tdTest.Attributes And dbAttachSavePWD) <> 0)) Then
                  strtb := strtb + suffix
              Else
              begin
                dbsDst.TableDefs.Delete( strtb);
              end;
            end;
          end;
          strConnect := ';DATABASE='+ srcName + ';pwd=' + srcPwd;
          tdfLinked := dbsDst.CreateTableDef(strtb,0,tdfLoop.name, strConnect);
          dbsDst.TableDefs.Append(tdfLinked);
        end;
      end;
    end;

    end.
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

    快速回复 返回顶部 返回列表