Windows XP专业版 ActiveState Perl 5.14.4 M $ Access 2010
我有一个accdb格式的Access数据库,其中包含一个数字 存储的查询。我想使用Perl将它们解压缩到平面文件。
查询的名称出现在[MSysObjects]。[Name]中 它们本身似乎以某种方式存储在MSysQueries中。
但我的问题是上游 - 我无法读取这些表中的任何一个。 我已经确认,当我直接打开数据库时,用户名为“Admin”。
谷歌搜索出现了http://t1134.codeinpro.us/q/5080f5c04f1eba38a4d1547b, 这说明“Admin”没有MSysObjects的SELECT权限所以我需要 执行DDL语句到GRANT SELECT ON MSysObjects TO Admin
更多的谷歌搜索出现了http://www.connectionstrings.com/access-2010 要启用GRANT我需要添加的某些管理语句 UID =管理员; PWD =; ExtendedAnsiSQL = 1; 到我的连接字符串
同一页面有一个专门说明工作组文件所在位置的模糊信息 位于 SystemDB = C:\ mydatabase.mdw 在连接字符串中。 稍等一下。
所以我有了这个
#! /home/gnu/bin/perl
#
package main;
use strict;
use autouse 'Data::Dumper' => qw(Dumper);
use DBI;
use DBD::ODBC; # works for both access and sql server
use Win32::ODBC;
use OLE;
use Win32::OLE;
# prototypes
sub _setUpDatabaseHandle_Access_Local_EnableAdminStatements($);
sub setPermissionsOnTables($);
sub readTableMSysObjects($);
#globals
my $debug = 1;
my $targetDbFile = undef;
my $dbh_C = undef;
print "version of DBD::ODBC is ".$DBD::ODBC::VERSION."\n";
print "version of Win32::ODBC is ".$Win32::ODBC::VERSION."\n";
print "version of Win32::OLE is ".$Win32::OLE::VERSION."\n";
$targetDbFile = "C:/putyer/msaccessdb/here.accdb";
$dbh_C = _setUpDatabaseHandle_Access_Local_EnableAdminStatements( $targetDbFile);
setPermissionsOnTables( $dbh_C);
readTableMSysObjects( $dbh_C);
$dbh_C->disconnect() if( defined( $dbh_C));
exit(0);
#-------------------------------
# when you use perl to open an .accdb Access database the Uid is always Admin
# But user Admin doesn't have SELECT permission on MSysObjects by default you must first
# grant the permission on the object for the user
# to enable certain admin commands like CREATE USER, GRANT, REVOKE, DEFAULTS when using CREATE TABLEs
sub _setUpDatabaseHandle_Access_Local_EnableAdminStatements($)
{
my ( $dbFile) = @_;
my $errorHit = 0;
my $conn_str = "DBI:ODBC:DRIVER={Microsoft Access Driver (*.mdb, *.accdb)};dbq=".$dbFile;
$conn_str .= "; Uid=Admin; Pwd=; ExtendedAnsiSQL=1";
my $dbh = DBI->connect( $conn_str);
if( !defined( $dbh)) {
print "db connection failed - ".$DBI::errstr."\n";
$errorHit = 1;
}
print "connection _setUpDatabaseHandle_Access_Local_EnableAdminStatements failed\n" if( $errorHit);
return $dbh;
}
#-------------------------------
sub setPermissionsOnTables($)
{
my ( $dbh) = @_;
print "entering setPermissionsOnTables\n" if $debug;
my $errorHit = 0;
my $q = undef;
my $sth = undef;
unless( $errorHit) {
$q = "GRANT SELECT ON MSysObjects TO Admin";
$sth = $dbh->prepare($q);
if( !defined( $sth)) {
print "sth failed to define - ".$DBI::errstr."\n";
$errorHit = 1;
} else {
$sth->execute(); # <=== FAILS HERE
if( my $errorMsg = $dbh->errstr ) {
print "select statement failed - ".$errorMsg."\n";
$errorHit = 1;
}
}
}
unless( $errorHit) {
$q = "GRANT SELECT ON MSysQueries TO Admin";
$sth = $dbh->prepare($q);
if( !defined( $sth)) {
print "sth failed to define - ".$DBI::errstr."\n";
$errorHit = 1;
} else {
$sth->execute();
if( my $errorMsg = $dbh->errstr ) {
print "select statement failed - ".$errorMsg."\n";
$errorHit = 1;
}
}
}
print "exiting setPermissionsOnTables with errorHit=".$errorHit."\n" if $debug;
return $errorHit;
}
#-------------------------------
sub readTableMSysObjects($)
{
my ($dbh) = @_;
print "entering readTableMSysObjects\n" if $debug;
my $errorHit = 0;
my $q = undef;
my $sth = undef;
unless( $errorHit) {
$q = "SELECT * FROM MSysObjects"; # remember that db nulls come over as perl undefs
$sth = $dbh->prepare($q);
if( !defined( $sth)) {
print "sth failed to define - ".$DBI::errstr."\n";
$errorHit = 1;
} else {
$sth->execute();
if( my $errorMsg = $dbh->errstr ) {
print "select statement failed - ".$errorMsg."\n";
$errorHit = 1;
} else {
if( $sth->rows == 0 ) {
print "select statement returned 0 rows\n";
$errorHit = 1;
} else {
my $row_hashref = undef;
while( $row_hashref = $sth->fetchrow_hashref() ) {
print Dumper( $row_hashref);
}
}
}
$sth->finish();
}
}
print "exiting readTableMSysObjects\n" if $debug;
return $errorHit;
}
在尝试执行臭名昭着的第一个GRANT时失败 无法打开Microsoft Access数据库引擎工作组信息文件 信息。
所以看来我也需要这个文件,我似乎无法在我的盒子上找到它。 或者我应该/应该使用不同的连接?像其中一个?
#-------------------------------
sub _setUpDatabaseHandle_Access_Local_ADO_ACE($)
{
my ( $dbFile) = @_;
my $errorHit = 0;
my $conn_str = "DBI:ADO:Provider=Microsoft.ACE.OLEDB.12.0;Data Source=".$dbFile;
$conn_str .= "; Persist Security Info=False";
# print $conn_str."\n";
my $dbh = DBI->connect( $conn_str);
if( !defined( $dbh)) {
_pushErrorMsg("db connection failed - ".$DBI::errstr);
$errorHit = 1;
}
print "connection _setUpDatabaseHandle_Access_Local_ACE failed\n" if( $errorHit);
return $dbh;
}
#-------------------------------
sub _setUpDatabaseHandle_Access_Local_ADO($)
{
my ( $dbFile) = @_;
my $errorHit = 0;
my $conn_str = "DBI:ADO:File Name=".$dbFile;
my $username = undef;
my $password = undef;
my $dbh = DBI->connect( $conn_str, $username, $password);
if( !defined( $dbh)) {
_pushErrorMsg("db connection failed - ".$DBI::errstr);
$errorHit = 1;
}
print "connection _setUpDatabaseHandle_Access_Local_ADO failed\n" if( $errorHit);
return $dbh;
}
任何指针/提示/建设性批评,特别是例子都是受欢迎的。
TIA,
仍在学习史蒂夫
答案 0 :(得分:1)
我的经验是Access数据库引擎和相关驱动程序似乎可以访问ADO和OleDb中非常紧密锁定的[MSys ...]表。它们似乎仍然可以通过DAO访问,但是如果你使用DAO那么你真的不需要对[MSysObjects]大惊小怪,因为你可以遍历QueryDefs
集合。
以下VBScript将每个Query的SQL代码转储到单独的文本文件中。您可以通过
将它集成到Perl项目中cscript.exe
)。Option Explicit
Dim dbe ' As DAO.DBEngine
Dim db ' As DAO.Database
Dim qdf ' As DAO.QueryDef
Dim fso ' As FileSystemObject
Dim f ' As TextStream
Set fso = CreateObject("Scripting.FileSystemObject") ' New FileSystemObject
Set dbe = CreateObject("DAO.DBEngine.120") ' New DAO.DBEngine
Set db = dbe.OpenDatabase("C:\__tmp\main.accdb")
For Each qdf In db.QueryDefs
Set f = fso.CreateTextFile("C:\__tmp\" & qdf.Name & ".sql")
f.WriteLine qdf.SQL
f.Close
Set f = Nothing
Next
db.Close
Set db = Nothing
Set dbe = Nothing
Set fso = Nothing