Patch: Auto-generate search_path statement for selected schema in query editor - Mailing list pgadmin-hackers
From | Florian Klaar |
---|---|
Subject | Patch: Auto-generate search_path statement for selected schema in query editor |
Date | |
Msg-id | 51151EEE.2030908@gmx.de Whole thread Raw |
Responses |
Re: Patch: Auto-generate search_path statement for
selected schema in query editor
|
List | pgadmin-hackers |
Hi all, Recently I wrote a small patch for frmQuery.cpp in order to auto-generate a "SET search_path TO ..." statement when opening the query editor with a schema-related object selected in the object browser, e.g. a table, function or sequence (or their respective collections). The reason being that in our company, after migrating from MSSQL Server to pg, we use a single database for many of our customers, with one schema per customer and identically named objects within those schemas. E.g. cust_schema_01.table_x, cust_schema_02.table_x, cust_schema_03.table_x. For maintenance and debugging, we connect to the database using the postgres superuser account in pgAdmin3. Now in order to access table_x within a certain customer's schema in the query editor, we always have to prepend the schema name to the table name or issue a "SET search_path TO cust_schema_nn,public" statement. This is rather tedious, so I came up with a patch for pgAdmin3 that tries to intelligently generate a search_path depending on the currently selected object in the object browser as well as depending on the existing search_path configured for the current database connection. That way, we can easily open query editors under different schemas without bothering about the search_path ourselves. This is what my code does when opening a new query editor window: - Check whether the currently selected object in the object browser is of type pgSchema, pgSchemaObject or pgSchemaObjCollection or one of their descendants which (if I'm not mistaken) means it does have a schema associated with it. - If so, it checks whether the schema belonging to this object is already contained in the user's search_path (case-sensitively and considering the $user placeholder). - If the schema isn't already in the user's search_path, the code generates a "SET search_path TO <selected_schema>,<existing_search_path>" statement and has it written into the newly opened query editor window. - After that, it places the cursor to the end of the sql text so the user can begin typing right away. Example: the user's search_path is set via ALTER ROLE to "foobar,public". Now the user selects a single table in the object browser underneath the schema "cust_schema_03" and opens a new query editor window. pgAdmin will now pre-fill the editor's input field with "SET search_path TO cust_schema_03,foobar,public;" and place the cursor two lines beneath that statement. Tested on Windows XP Pro SP3 and Windows7 Pro only - I didn't bother to create a build environment on my Linux box yet. In case you deem this patch useful, find the diff output based on the 1.16.1 release source code attached below. There may occur usability problems in combination with the existing "sticky SQL" option though. We don't use the "sticky SQL" feature in our environment, so for now I didn't spend too much thought on it. Beware also that though being a developer, I'm really inexperienced in C/C++ and completely new to wxWidgets and to the inner workings of pgAdmin, so there may well be room for improvement in my code. Having said that, I'd be willing to dig further into the pgAdmin3 code in order to make this a configurable option, integrate it better into the existing code etc. if need be. For now I egoistically tried to keep a small footprint for easier patchability in future pgAdmin releases (just in case this feature for one reason or another won't make it into the release branch anytime soon). What are your thoughts on this? Cheers from Germany and thanks a lot for all your nice work on pgAdmin and PostgreSQL. Florian frm\frmQuery.cpp, based on 1.16.1 release: 613a614,616 > // Jump to the end of the input field after placing code in it > sqlQuery->DocumentEnd(); > 3161a3165,3217 > > // Try to find the schema "obj" belongs to and then get its name. > // If obj is not of type pgSchema, pgSchemaObjCollection or pgSchemaObject (or one of their descendants), > // it obviously doesn't belong to any schema. > wxString schemaName; > pgSchema *schema = dynamic_cast<pgSchema*>(obj); > if(schema) > { > // We have a schema right there. Easy. > schemaName = schema->GetName(); > } > else > { > // It's not a schema, so check if it's a descendant of pgSchemaObjCollection (e.g. a "Tables" or "Functions" node) > pgSchemaObjCollection *schemaObjColl = dynamic_cast<pgSchemaObjCollection*>(obj); > if(schemaObjColl) > schemaName = schemaObjColl->GetSchema()->GetName(); > else > { > // Not a pgSchemaObjCollection either, so check if it's a descendant of pgSchemaObject (e.g. a single tableor function) > pgSchemaObject *schemaObj = dynamic_cast<pgSchemaObject*>(obj); > if(schemaObj) > schemaName = schemaObj->GetSchema()->GetName(); > } > } > if(!schemaName.IsEmpty()) > { > // We found a schema for the selected object, so check if it's already contained in search_path and build a "SETsearch_path" statement otherwise. > // First though, check whether the schema name contains upper-case characters and therefore needs to be enclosedin quotation marks. > if(schemaName != schemaName.Lower()) > schemaName = schemaName.Prepend(wxT("\"")).Append(wxT("\"")); > // Now compare it to the current search_path > wxString searchPath = obj->GetDatabase()->GetSearchPath(); > wxStringTokenizer searchPathTokenizer(searchPath, wxT(",")); > bool schemaContainedInSearchPath = false; > while(searchPathTokenizer.HasMoreTokens()) > { > wxString currentToken = searchPathTokenizer.GetNextToken(); > if(currentToken == schemaName || (currentToken == wxT("\"$user\"") && schemaName == obj->GetConnection()->GetUser())) > { > schemaContainedInSearchPath = true; > break; > } > } > if(!schemaContainedInSearchPath) > { > // Schema not contained in search_path, so build a statement for it. > // Since a user's search_path is never empty (?), we can safely put a comma between our current schema nameand the user's current search_path > // without checking for an empty string. > qry = wxT("SET search_path TO ") + schemaName + wxT(",") + searchPath + wxT(";\n\n"); > } > } > 3163c3219,3220 < qry = obj->GetSql(form->GetBrowser()); --- > qry += obj->GetSql(form->GetBrowser()); >
pgadmin-hackers by date: