def GetInstrumentQuery(server): sql="""SELECT 'snippet_table', relname FROM pg_class JOIN pg_namespace nsp ON nsp.oid=relnamespace WHERE nspname=%(adminspace)s AND relname=%(snippet_table)s""" % { 'adminspace': quoteValue(server.GetPreference("AdminNamespace")), 'snippet_table': quoteValue("Admin_Snippet_%s" % server.user) } return sql
def GetInstrumentQuery(server): sql = """SELECT 'querypreset_table', relname FROM pg_class JOIN pg_namespace nsp ON nsp.oid=relnamespace WHERE nspname=%(adminspace)s AND relname=%(querypreset_table)s""" % { "adminspace": quoteValue(server.GetPreference("AdminNamespace")), "querypreset_table": quoteValue("Admin_QueryPreset_%s" % server.user), } return sql
def Save(self): name = self.vals['name'] val = self.GetVal() cursor = self.server.GetCursor() self.SetStatus(xlt("Setting value...")) if self.page.lastNode.version < 9.4: cfg = {} file = cursor.ExecuteSingle( "SELECT pg_read_file('postgresql.auto.conf', 0, 999999)") for line in file.splitlines(): if line.startswith('#') or not line.strip( ) or line == InstrumentConfig.autoconfLine: continue n, _, v = line.partition('=') cfg[n] = v cfg[name] = "'%s'" % val lines = [InstrumentConfig.autoconfHeader] for name, val in cfg.items(): lines.append("%s=%s" % (name, val)) lines.append("") cursor.ExecuteSingle(""" SELECT pg_file_unlink('postgresql.auto.conf.bak'); SELECT pg_file_write('postgresql.auto.conf.tmp', %s, false); SELECT pg_file_rename('postgresql.auto.conf.tmp', 'postgresql.auto.conf', 'postgresql.auto.conf.bak'); """ % quoteValue("\n".join(lines))) else: cursor.ExecuteSingle("ALTER SYSTEM SET %s=%s" % (name, quoteValue(val, cursor))) self.page.SetProperty(name, val) if self.Reload: self.page.DoReload() return True
def DoInstrument(server): if server.version >= 8.1 and server.version < 9.4: if not server.GetValue('adminpack'): if server.GetValue('adminpack-extension'): server.GetCursor().ExecuteSingle( "CREATE EXTENSION adminpack") else: cursor = server.GetCursor() cursor.ExecuteSingle(""" CREATE OR REPLACE FUNCTION pg_catalog.pg_file_write(text, text, bool) RETURNS bigint AS '$libdir/adminpack', 'pg_file_write' LANGUAGE C VOLATILE STRICT; CREATE OR REPLACE FUNCTION pg_catalog.pg_file_rename(text, text, text) RETURNS bool AS '$libdir/adminpack', 'pg_file_rename' LANGUAGE C VOLATILE; CREATE OR REPLACE FUNCTION pg_catalog.pg_file_unlink(text) RETURNS bool AS '$libdir/adminpack', 'pg_file_unlink' LANGUAGE C VOLATILE STRICT; """) if not server.GetValue('postgresql.auto.conf'): cursor = server.GetCursor() cursor.ExecuteSingle( "SELECT pg_file_write('postgresql.auto.conf', %s, false)" % quoteValue(InstrumentConfig.autoconfHeader, cursor)) if server.GetValue('admin4.instrumentation') != 'ok': dataDir = server.GetValue("data_directory") autoconfPath = "%s/postgresql.auto.conf" % dataDir cfgFile = server.GetValue('config_file') if cfgFile.startswith(dataDir): cfgFile = cfgFile[len(dataDir) + 1:] cursor = server.GetCursor() cfg = cursor.ExecuteSingle( "SELECT pg_read_file('%s', 0, 999999)" % cfgFile) if not cfg.strip().endswith("include '%s'" % autoconfPath): cfg += "\n\n# Admin4 config file\ninclude '%s'\n" % autoconfPath cursor.ExecuteSingle(""" SELECT pg_file_unlink('%(cfg)s.bak'); SELECT pg_file_write('%(cfg)s.tmp', %(content)s, false); SELECT pg_file_rename('%(cfg)s.tmp', '%(cfg)s', '%(cfg)s.bak'); SELECT pg_reload_conf(); """ % { 'cfg': cfgFile, 'content': quoteValue(cfg, cursor) }) else: wx.MessageBox( xlt("""The main configuration file cannot be modified automatically because it is not located in the data directory.\nPlease edit %s and append the line \"include '%s\' \" at the very end.""" ) % (cfgFile, autoconfPath), xlt("Please modify %s manually") % cfgFile.split('/')[-1]) return True
def Save(self): name=self.vals['name'] val=self.GetVal() cursor=self.server.GetCursor() self.SetStatus(xlt("Setting value...")) if self.page.lastNode.version < 9.4: cfg={} file=cursor.ExecuteSingle("SELECT pg_read_file('postgresql.auto.conf', 0, 999999)") for line in file.splitlines(): if line.startswith('#') or not line.strip() or line == InstrumentConfig.autoconfLine: continue n,_,v = line.partition('=') cfg[n]=v cfg[name]="'%s'" % val lines=[InstrumentConfig.autoconfHeader] for name, val in cfg.items(): lines.append("%s=%s" % (name, val)) lines.append("") cursor.ExecuteSingle(""" SELECT pg_file_unlink('postgresql.auto.conf.bak'); SELECT pg_file_write('postgresql.auto.conf.tmp', %s, false); SELECT pg_file_rename('postgresql.auto.conf.tmp', 'postgresql.auto.conf', 'postgresql.auto.conf.bak'); """ % quoteValue("\n".join(lines))) else: cursor.ExecuteSingle("ALTER SYSTEM SET %s=%s" % (name, quoteValue(val, cursor))) self.page.SetProperty(name, val) if self.Reload: self.page.DoReload() return True
def getCommentDef(self): if self.info['description']: return [ "COMMENT ON " + self.ObjectSql() + " IS " + quoteValue(self.info['description']) + ";" ] return []
def Delete(self, rows): """ Delete(rows) expects rows in reverse sorted order """ query=pgQuery(self.tableSpecs.tabName, self.tableSpecs.GetCursor()) all=[] for row in rows: wh=[] for colname in self.tableSpecs.keyCols: wh.append("%s=%s" % (quoteIdent(colname), quoteValue(self.rows[row][colname]))) all.append("(%s)" % " AND ".join(wh)) query.AddWhere("\n OR ".join(all)) rc=query.Delete() self.grid.Freeze() self.grid.BeginBatch() for row in rows: self.grid.DeleteRows(row, 1, True) # msg=wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED) self.grid.EndBatch() self.grid.ForceRefresh() self.grid.Thaw() return rc
def GrantCommentSql(self): str = "" acl = self.info.get('acl') if acl: for grant in shlexSplit(acl[1:-1], ','): if grant.startswith('='): user = "******" rest = grant[1:] else: user, rest = shlexSplit(grant, '=') user = quoteIdent(user) rights = shlexSplit(rest, '/')[0] if rights == self.allGrants: rights = "ALL" else: rightlist = [] for right in rights: rightlist.append(rightString[right]) rights = ",".join(rightlist) str += "GRANT %s ON %s TO %s\n" % (rights, self.ObjectSql(), user) des = self.info.get('description') if des: str += "\nCOMMENT ON %s IS %s\n" % (self.ObjectSql(), quoteValue(des)) return str
def GrantCommentSql(self): str="" acl=self.info.get('acl') if acl: for grant in shlexSplit(acl[1:-1], ','): if grant.startswith('='): user="******" rest=grant[1:] else: user, rest=shlexSplit(grant, '=') user=quoteIdent(user) rights=shlexSplit(rest, '/')[0] if rights == self.allGrants: rights="ALL" else: rightlist=[] for right in rights: rightlist.append(rightString[right]) rights=",".join(rightlist) str += "GRANT %s ON %s TO %s\n" % (rights, self.ObjectSql(), user) des=self.info.get('description') if des: str += "\nCOMMENT ON %s IS %s\n" % (self.ObjectSql(), quoteValue(des)) return str
def Delete(self, rows): """ Delete(rows) expects rows in reverse sorted order """ query = pgQuery(self.tableSpecs.tabName, self.tableSpecs.GetCursor()) all = [] for row in rows: wh = [] for colname in self.tableSpecs.keyCols: wh.append( "%s=%s" % (quoteIdent(colname), quoteValue(self.rows[row][colname]))) all.append("(%s)" % " AND ".join(wh)) query.AddWhere("\n OR ".join(all)) rc = query.Delete() self.grid.Freeze() self.grid.BeginBatch() for row in rows: self.grid.DeleteRows(row, 1, True) # msg=wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED) self.grid.EndBatch() self.grid.ForceRefresh() self.grid.Thaw() return rc
def RereadServerInfo(self): parts = [ """ SELECT name, setting FROM pg_settings WHERE name in ('autovacuum', 'log_line_prefix', 'log_destination', 'logging_collector', 'log_directory', 'data_directory', 'config_file') UNION SELECT 'version', version() UNION SELECT 'lastsysoid', datlastsysoid::text FROM pg_database WHERE datname=%(datname)s UNION SELECT proname, proname FROM pg_proc WHERE proname IN ( %(adminprocs)s ) AND pronamespace=11 UNION SELECT 'adminspace', nspname FROM pg_namespace WHERE nspname=%(adminspace)s UNION SELECT 'fav_table', relname FROM pg_class JOIN pg_namespace nsp ON nsp.oid=relnamespace WHERE nspname=%(adminspace)s AND relname=%(fav_table)s """ % { 'datname': quoteValue(self.maintDb), 'adminspace': quoteValue(self.GetPreference("AdminNamespace")), 'fav_table': quoteValue("Admin_Fav_%s" % self.user), 'adminprocs': ", ".join(map(lambda p: "'%s'" % p, adminProcs)) } ] # check instrumentation of tools for menu in self.moduleinfo().get('menus', []): cls = menu['class'] if hasattr(cls, 'GetInstrumentQuery'): iq = cls.GetInstrumentQuery(self) if iq: parts.append(iq) query = "\nUNION\n".join(parts) self.info = self.connection.GetCursor().ExecuteDict(query) self.adminspace = self.info.get('adminspace') fav_table = self.info.get('fav_table') if fav_table: self.fav_table = "%s.%s" % (quoteIdent( self.adminspace), quoteIdent(fav_table)) else: self.fav_table = None
def GetSql(self): sql=[] params={ "colname": quoteIdent(self.ColName), "oldcol": quoteIdent(self['ColName'].unchangedValue)} if self.HasChanged("ColName"): sql.append("RENAME COLUMN %(oldcol)s TO %(colname)s" % params) if self.HasChanged("NotNull"): if self.NotNull: params['val'] = "SET" else: params['val'] = "DROP" sql.append("ALTER COLUMN %(colname)s %(val)s NOT NULL" % params) if self.HasChanged("DefaultVal"): if self.DefaultVal: params['default'] = self.DefaultVal sql.append("ALTER COLUMN %(colname)s SET DEFAULT %(default)s" % params) else: sql.append("ALTER COLUMN (%colname)s DROP DEFAULT" % params) if self.HasChanged("DataType Collation Length Precision"): params['type']=self['DataType'].GetValue() n="ALTER COLUMN %(colname)s TYPE %(type)s" % params precFlag=self.typeInfo.get(self.DataType) if precFlag and self.Length: n += "(%d" % self.Length if precFlag == 2 and self['Precision'].GetValue(): n += ", %d" % self.Precision n += ")" if self.HasChanged("Collation"): n += " COLLATE %s" % quoteIdent(self['Collation'].GetValue()) sql.append(n) if self.HasChanged("Statistics"): params['val'] = self.Statistics sql.append("ALTER COLUMN %(colname)s SET STATISTICS %(val)d" % params) # type, len, prec, collate # if self.HasChanged("Collation"): # params['val'] = self["Collation"].GetValue() # sql.append("ALTER COLUMN %(colname)s SET COLLATE \"%(val)d\";" % params) if sql: sql=["ALTER TABLE %s\n %s;" % (self.dialog.node.NameSql() , ",\n ".join(sql))] if self.HasChanged('Comment'): params['tabname'] = self.dialog.node.NameSql() params['comment'] = quoteValue(self.Comment) sql.append("COMMENT ON COLUMN %(tabname)s.%(colname)s IS %(comment)s" % params) if sql: return "\n".join(sql) return ""
def RereadServerInfo(self): parts=[""" SELECT name, setting FROM pg_settings WHERE name in ('autovacuum', 'log_line_prefix', 'log_destination', 'logging_collector', 'log_directory', 'data_directory', 'config_file') UNION SELECT 'version', version() UNION SELECT 'lastsysoid', datlastsysoid::text FROM pg_database WHERE datname=%(datname)s UNION SELECT proname, proname FROM pg_proc WHERE proname IN ( %(adminprocs)s ) AND pronamespace=11 UNION SELECT 'adminspace', nspname FROM pg_namespace WHERE nspname=%(adminspace)s UNION SELECT 'fav_table', relname FROM pg_class JOIN pg_namespace nsp ON nsp.oid=relnamespace WHERE nspname=%(adminspace)s AND relname=%(fav_table)s """ % {'datname': quoteValue(self.maintDb), 'adminspace': quoteValue(self.GetPreference("AdminNamespace")), 'fav_table': quoteValue("Admin_Fav_%s" % self.user), 'adminprocs': ", ".join(map(lambda p: "'%s'" % p, adminProcs)) }] # check instrumentation of tools for menu in self.moduleinfo().get('menus', []): cls=menu['class'] if hasattr(cls, 'GetInstrumentQuery'): iq=cls.GetInstrumentQuery(self) if iq: parts.append(iq) query="\nUNION\n".join(parts) self.info=self.connection.GetCursor().ExecuteDict(query) self.adminspace=self.info.get('adminspace') fav_table=self.info.get('fav_table') if fav_table: self.fav_table="%s.%s" % (quoteIdent(self.adminspace), quoteIdent(fav_table)) else: self.fav_table=None
def DoInstrument(server): if server.version >= 8.1 and server.version < 9.4: if not server.GetValue('adminpack'): if server.GetValue('adminpack-extension'): server.GetCursor().ExecuteSingle("CREATE EXTENSION adminpack") else: cursor=server.GetCursor() cursor.ExecuteSingle(""" CREATE OR REPLACE FUNCTION pg_catalog.pg_file_write(text, text, bool) RETURNS bigint AS '$libdir/adminpack', 'pg_file_write' LANGUAGE C VOLATILE STRICT; CREATE OR REPLACE FUNCTION pg_catalog.pg_file_rename(text, text, text) RETURNS bool AS '$libdir/adminpack', 'pg_file_rename' LANGUAGE C VOLATILE; CREATE OR REPLACE FUNCTION pg_catalog.pg_file_unlink(text) RETURNS bool AS '$libdir/adminpack', 'pg_file_unlink' LANGUAGE C VOLATILE STRICT; """) if not server.GetValue('postgresql.auto.conf'): cursor=server.GetCursor() cursor.ExecuteSingle("SELECT pg_file_write('postgresql.auto.conf', %s, false)" % quoteValue(InstrumentConfig.autoconfHeader, cursor)) if server.GetValue('admin4.instrumentation') != 'ok': dataDir=server.GetValue("data_directory") autoconfPath="%s/postgresql.auto.conf" % dataDir cfgFile=server.GetValue('config_file') if cfgFile.startswith(dataDir): cfgFile=cfgFile[len(dataDir)+1:] cursor=server.GetCursor() cfg=cursor.ExecuteSingle("SELECT pg_read_file('%s', 0, 999999)" % cfgFile) if not cfg.strip().endswith("include '%s'" % autoconfPath): cfg += "\n\n# Admin4 config file\ninclude '%s'\n" % autoconfPath cursor.ExecuteSingle(""" SELECT pg_file_unlink('%(cfg)s.bak'); SELECT pg_file_write('%(cfg)s.tmp', %(content)s, false); SELECT pg_file_rename('%(cfg)s.tmp', '%(cfg)s', '%(cfg)s.bak'); SELECT pg_reload_conf(); """ % {'cfg': cfgFile, 'content': quoteValue(cfg, cursor) } ) else: wx.MessageBox(xlt("""The main configuration file cannot be modified automatically because it is not located in the data directory.\nPlease edit %s and append the line \"include '%s\' \" at the very end.""") % (cfgFile, autoconfPath), xlt("Please modify %s manually") % cfgFile.split('/')[-1]) return True
def AddFavourite(self, node, favgroup=None): query=pgQuery(self.fav_table, self.GetCursor()) query.AddColVal('dboid',node.GetDatabase().GetOid()) query.AddColVal('favoid', node.GetOid()) query.AddColVal('favtype', node.favtype) query.AddColVal('favgroup', favgroup) query.Insert() node.GetDatabase().favourites.append(node.GetOid()) return True self.GetCursor().ExecuteSingle( "INSERT INTO %(favtable)s (dboid, favoid, favtype, favgroup) VALUES (%(dboid)d, %(favoid)d, '%(favtype)s', %(favgroup)s)" % { 'favtable': self.fav_table, 'dboid': node.GetDatabase().GetOid(), 'favoid': node.GetOid(), 'favtype': node.favtype, 'favgroup': quoteValue(favgroup) } ) node.GetDatabase().favourites.append(node.GetOid()) return True
def AddFavourite(self, node, favgroup=None): query = pgQuery(self.fav_table, self.GetCursor()) query.AddColVal('dboid', node.GetDatabase().GetOid()) query.AddColVal('favoid', node.GetOid()) query.AddColVal('favtype', node.favtype) query.AddColVal('favgroup', favgroup) query.Insert() node.GetDatabase().favourites.append(node.GetOid()) return True self.GetCursor().ExecuteSingle( "INSERT INTO %(favtable)s (dboid, favoid, favtype, favgroup) VALUES (%(dboid)d, %(favoid)d, '%(favtype)s', %(favgroup)s)" % { 'favtable': self.fav_table, 'dboid': node.GetDatabase().GetOid(), 'favoid': node.GetOid(), 'favtype': node.favtype, 'favgroup': quoteValue(favgroup) }) node.GetDatabase().favourites.append(node.GetOid()) return True
def Go(self): cd = self.dialog.colDef self.ColName = cd['attname'] self.NotNull = cd['attnotnull'] self.DefaultVal = cd['adsrc'] self.Description = cd['description'] self.Statistics = cd['attstattarget'] type = cd['typename'] ci = type.find('(') if (ci > 0): prec = type[ci + 1:-1].split(',') self.Length = int(prec[0]) if len(prec) > 1: self.Precision = int(prec[1]) self.typeInfo = {} types = self.dialog.node.GetCursor().ExecuteDictList( "SELECT oid, typname, typmodin FROM pg_type WHERE typcategory=%s ORDER BY oid" % quoteValue(cd['typcategory'])) for t in types: oid = t['oid'] self["DataType"].AppendKey(t['oid'], t['typname']) if t['typmodin'] != '-': precFlag = 1 else: precFlag = 0 self.typeInfo[oid] = precFlag self.DataType = cd['atttypid'] if cd['atttypid'] in (20, 23) or cd['typbasetype'] in (20, 23): if cd['sername']: if cd['serschema'] != 'public': sn = "%(serschema)s.%(sername)s" % cd else: sn = cd['sername'] self['Sequence'].Append(sn) self.Sequence = sn else: self['Sequence'].Disable() if self.dialog.GetServer().version >= 9.1: if cd['typcategory'] == 'S': colls = self.dialog.node.GetCursor().ExecuteDictList( "SELECT oid,collname FROM pg_collation WHERE collencoding IN (-1, %d) ORDER BY oid" % self.dialog.node.GetDatabase().info['encoding']) for c in colls: self['Collation'].AppendKey(c['oid'], c['collname']) if cd['attcollation']: self.Collation = cd['attcollation'] else: self['Collation'].Disable() else: self.ShowControls("Collation", False) self.Comment = cd['description'] # Not yet supported self.ShowControls("Sequence Storage Statistics", False) self.OnTypeChange(None) self.SetUnchanged()
def getCommentDef(self): if self.info['description']: return ["COMMENT ON " + self.ObjectSql() + " IS " + quoteValue(self.info['description']) + ";"] return []
def Go(self): cd=self.dialog.colDef self.ColName = cd['attname'] self.NotNull = cd['attnotnull'] self.DefaultVal=cd['adsrc'] self.Description=cd['description'] self.Statistics = cd['attstattarget'] type=cd['typename'] ci=type.find('(') if (ci > 0): prec=type[ci+1:-1].split(',') self.Length=int(prec[0]) if len(prec) > 1: self.Precision = int(prec[1]) self.typeInfo={} types=self.dialog.node.GetCursor().ExecuteDictList("SELECT oid, typname, typmodin FROM pg_type WHERE typcategory=%s ORDER BY oid" % quoteValue(cd['typcategory'])) for t in types: oid=t['oid'] self["DataType"].AppendKey(t['oid'], t['typname']) if t['typmodin'] != '-': precFlag=1 else: precFlag=0 self.typeInfo[oid] = precFlag self.DataType=cd['atttypid'] if cd['atttypid'] in (20, 23) or cd['typbasetype'] in (20,23): if cd['sername']: if cd['serschema'] != 'public': sn="%(serschema)s.%(sername)s" % cd else: sn=cd['sername'] self['Sequence'].Append(sn) self.Sequence=sn else: self['Sequence'].Disable() if self.dialog.GetServer().version >= 9.1: if cd['typcategory'] == 'S': colls=self.dialog.node.GetCursor().ExecuteDictList( "SELECT oid,collname FROM pg_collation WHERE collencoding IN (-1, %d) ORDER BY oid" % self.dialog.node.GetDatabase().info['encoding']) for c in colls: self['Collation'].AppendKey(c['oid'], c['collname']) if cd['attcollation']: self.Collation = cd['attcollation'] else: self['Collation'].Disable() else: self.ShowControls("Collation", False) self.Comment=cd['description'] # Not yet supported self.ShowControls("Sequence Storage Statistics", False) self.OnTypeChange(None) self.SetUnchanged()
def GetSql(self): sql = [] params = { "colname": quoteIdent(self.ColName), "oldcol": quoteIdent(self['ColName'].unchangedValue) } if self.HasChanged("ColName"): sql.append("RENAME COLUMN %(oldcol)s TO %(colname)s" % params) if self.HasChanged("NotNull"): if self.NotNull: params['val'] = "SET" else: params['val'] = "DROP" sql.append("ALTER COLUMN %(colname)s %(val)s NOT NULL" % params) if self.HasChanged("DefaultVal"): if self.DefaultVal: params['default'] = self.DefaultVal sql.append("ALTER COLUMN %(colname)s SET DEFAULT %(default)s" % params) else: sql.append("ALTER COLUMN (%colname)s DROP DEFAULT" % params) if self.HasChanged("DataType Collation Length Precision"): params['type'] = self['DataType'].GetValue() n = "ALTER COLUMN %(colname)s TYPE %(type)s" % params precFlag = self.typeInfo.get(self.DataType) if precFlag and self.Length: n += "(%d" % self.Length if precFlag == 2 and self['Precision'].GetValue(): n += ", %d" % self.Precision n += ")" if self.HasChanged("Collation"): n += " COLLATE %s" % quoteIdent(self['Collation'].GetValue()) sql.append(n) if self.HasChanged("Statistics"): params['val'] = self.Statistics sql.append("ALTER COLUMN %(colname)s SET STATISTICS %(val)d" % params) # type, len, prec, collate # if self.HasChanged("Collation"): # params['val'] = self["Collation"].GetValue() # sql.append("ALTER COLUMN %(colname)s SET COLLATE \"%(val)d\";" % params) if sql: sql = [ "ALTER TABLE %s\n %s;" % (self.dialog.node.NameSql(), ",\n ".join(sql)) ] if self.HasChanged('Comment'): params['tabname'] = self.dialog.node.NameSql() params['comment'] = quoteValue(self.Comment) sql.append( "COMMENT ON COLUMN %(tabname)s.%(colname)s IS %(comment)s" % params) if sql: return "\n".join(sql) return ""