############## Python Objects ############## .. currentModule:: fbcore Using database objects in PowerConsole ====================================== Firebird Pack uses library :mod:`fbcore` build on top of KInterbasDB_ database driver, that defines set of higher-level objects to work with Firebird databases instead `classic` `Python Database API`_, and above all, represents database metadata as Python objects. Each connected database (represented by :class:`Database` object) is also accessible in PowerConsole's user space for direct use. You may specify the name under which it would be available using :keyword:`AS` clause of :keyword:`CONECT` or :keyword:`CREATE DATABASE` statements, otherwise it would get the default name "db". You may use these objects directly at command propt, in your PowerConsole scripts or pass them as parameters to PowerConsole commands. Here are some examples: 1. List names and owners of all user tables >>> connect 'employee' user 'sysdba' password 'masterkey' Database employee as db, user sysdba >>> list name,owner_name in db.tables name owner_name ================ ========== COUNTRY SYSDBA JOB SYSDBA DEPARTMENT SYSDBA EMPLOYEE SYSDBA PROJECT SYSDBA CUSTOMER SYSDBA EMPLOYEE_PROJECT SYSDBA PROJ_DEPT_BUDGET SYSDBA SALARY_HISTORY SYSDBA SALES SYSDBA 2. List all indices on JOB table >>> connect 'employee' user 'sysdba' password 'masterkey' Database employee as db, user sysdba >>> t = db.getTable('JOB') >>> list t.indices RDB$PRIMARY2 unique system index on JOB(JOB_CODE,JOB_GRADE,JOB_COUNTRY) RDB$FOREIGN3 system(FK) index on JOB(JOB_COUNTRY) MINSALX index on JOB(JOB_COUNTRY,MIN_SALARY) MAXSALX index on JOB(JOB_COUNTRY,MAX_SALARY) 3. Because Firebird Pack installs `object renderers` to your PowerConsole environment, you may see enhanced output for these objects when they're `evaluated` on command prompt:: >>> t = db.getTable('JOB') >>> t Table JOB (129) owned by SYSDBA JOB_CODE (JOBCODE) VARCHAR(5) Not Null CHECK (VALUE > '99999') JOB_GRADE (JOBGRADE) SMALLINT Not Null CHECK (VALUE BETWEEN 0 AND 6) JOB_COUNTRY (COUNTRYNAME) VARCHAR(15) Not Null JOB_TITLE VARCHAR(25) Not Null MIN_SALARY (SALARY) NUMERIC(10, 2) Not Null DEFAULT 0 CHECK (VALUE > 0) MAX_SALARY (SALARY) NUMERIC(10, 2) Not Null DEFAULT 0 CHECK (VALUE > 0) JOB_REQUIREMENT BLOB segment 400, subtype TEXT Nullable LANGUAGE_REQ ARRAY OF [5] VARCHAR(15) Nullable Constraints: PRIMARY KEY INTEG_10: Index RDB$PRIMARY2(JOB_CODE,JOB_GRADE,JOB_COUNTRY) FOREIGN KEY INTEG_11: Index RDB$FOREIGN3(JOB_COUNTRY) References COUNTRY RDB$PRIMARY1(COUNTRY) CHECK INTEG_12: CHECK (min_salary < max_salary) Indices: RDB$PRIMARY2 unique system index on (JOB_CODE,JOB_GRADE,JOB_COUNTRY) RDB$FOREIGN3 system(FK) index on (JOB_COUNTRY) MINSALX index on (JOB_COUNTRY,MIN_SALARY) MAXSALX index on (JOB_COUNTRY,MAX_SALARY) 4. List all triggers that post events >>> connect 'employee' user 'sysdba' password 'masterkey' Database employee as db, user sysdba >>> list name in (t for t in db.triggers if 'POST_EVENT' in t.source) name ============== POST_NEW_ORDER 5. Show procedures that are not in another database >>> connect 'employee' user 'sysdba' password 'masterkey' Database employee as db, user sysdba >>> connect '/data/db/employee-copy.fdb' user 'sysdba' password 'masterkey' as db2 Database /data/db/employee-copy.fdb as db2, user sysdba >>> ready db Main database set to db >>> list name in (p for p in db.procedures if db2.getProcedure(p.name) is None) name ========== MAIL_LABEL >>> list name in (p for p in db.procedures if not db2.getProcedure(p.name)) name ========== MAIL_LABEL 6. Find out what procedures differ in source code and then show the differences:: >>> connect 'employee' user 'sysdba' password 'masterkey' Database employee as db, user sysdba >>> connect '/data/db/employee-copy.fdb' user 'sysdba' password 'masterkey' as db2 Database /data/db/employee-copy.fdb as db2, user sysdba >>> ready db Main database set to db >>> common_proc = [p for p in db.procedures if db2.getProcedure(p.name)] >>> list name in common_proc name =============== GET_EMP_PROJ ADD_EMP_PROJ SUB_TOT_BUDGET DELETE_EMPLOYEE DEPT_BUDGET ORG_CHART SHIP_ORDER SHOW_LANGS ALL_LANGS >>> different = [p for p in common_proc if p.source != db2.getProcedure(p.name).source] >>> list name in different name =========== DEPT_BUDGET >>> params = zip(different,map(db2.getProcedure,(p.name for p in different))) >>> import difflib >>> list difflib.ndiff(params[0][0].source.split('\n'),params[0][1].source.split('\n')) - DECLARE VARIABLE sumb DECIMAL(12, 2); ? - + DECLARE VARIABLE sumb DECIMAL(12, 2); DECLARE VARIABLE rdno CHAR(3); DECLARE VARIABLE cnt INTEGER; BEGIN - tot = 0; + total = 0; ? ++ - SELECT budget FROM department WHERE dept_no = :dno INTO :tot; + SELECT budget FROM department WHERE dept_no = :dno INTO :total; ? ++ SELECT count(budget) FROM department WHERE head_dept = :dno INTO :cnt; IF (cnt = 0) THEN SUSPEND; FOR SELECT dept_no FROM department WHERE head_dept = :dno INTO :rdno DO BEGIN EXECUTE PROCEDURE dept_budget :rdno RETURNING_VALUES :sumb; - tot = tot + sumb; + total = total + sumb; ? ++ ++ END SUSPEND; END If you want to use it more often, you can save a lot of typing with handy function:: >>> def source_diff(a,b): ... result = ['Procedure %s' % a.name] ... result.extend(difflib.ndiff(a.source.split('\n'),b.source.split('\n'))) ... return '\n'.join(result) ... >>> list map(source_diff,different,map(db2.getProcedure,(p.name for p in different))) Procedure DEPT_BUDGET - DECLARE VARIABLE sumb DECIMAL(12, 2); ? - + DECLARE VARIABLE sumb DECIMAL(12, 2); DECLARE VARIABLE rdno CHAR(3); DECLARE VARIABLE cnt INTEGER; BEGIN - tot = 0; + total = 0; ? ++ - SELECT budget FROM department WHERE dept_no = :dno INTO :tot; + SELECT budget FROM department WHERE dept_no = :dno INTO :total; ? ++ SELECT count(budget) FROM department WHERE head_dept = :dno INTO :cnt; IF (cnt = 0) THEN SUSPEND; FOR SELECT dept_no FROM department WHERE head_dept = :dno INTO :rdno DO BEGIN EXECUTE PROCEDURE dept_budget :rdno RETURNING_VALUES :sumb; - tot = tot + sumb; + total = total + sumb; ? ++ ++ END SUSPEND; END If you know that both databases have the same procedures that just differ in source, you may write:: >>> list map(source_diff,db.procedures,db2.procedures) to list **all** procedures that differ in source including the diff report. .. Tip:: You can create your own library from these functions and import them any time to the PowerConsole. You can even use PowerConsole commands in these libraries, but in that case you have to install them to your interactive session via PowerConsole's :keyword:`RUN` command. Available objects ================= .. index:: pair: DATABASE; (python object) Database -------- .. autoclass:: Database :member-order: groupwise :members: :inherited-members: Database File ------------- .. autoclass:: DbFile :member-order: groupwise :members: :inherited-members: .. index:: pair: CHARACTER SET; (python object) Character Set ------------- .. autoclass:: CharacterSet :member-order: groupwise :members: :inherited-members: .. index:: pair: COLLATION; (python object) Collation --------- .. autoclass:: Collation :member-order: groupwise :members: .. index:: pair: DOMAIN; (python object) Domain ------ .. autoclass:: Domain :member-order: groupwise :members: .. index:: pair: TABLE; (python object) Table ----- .. autoclass:: Table :member-order: groupwise :members: Table Column ------------ .. autoclass:: TableColumn :member-order: groupwise :members: Table Constraint ---------------- .. autoclass:: Constraint :member-order: groupwise :members: .. index:: pair: INDEX; (python object) Index ----- .. autoclass:: Index :member-order: groupwise :members: .. index:: pair: VIEW; (python object) View ---- .. autoclass:: View :member-order: groupwise :members: View Column ----------- .. autoclass:: ViewColumn :member-order: groupwise :members: .. index:: pair: TRIGGER; (python object) Trigger ------- .. autoclass:: Trigger :member-order: groupwise :members: .. index:: pair: PROCEDURE; (python object) Stored Procedure ---------------- .. autoclass:: Procedure :member-order: groupwise :members: Procedure Parameter ------------------- .. autoclass:: ProcParameter :member-order: groupwise :members: .. index:: pair: EXCEPTION; (python object) Exception --------- .. autoclass:: Exception :member-order: groupwise :members: .. index:: pair: GENERATOR; (python object) Generator --------- .. autoclass:: Generator :member-order: groupwise :members: .. index:: pair: ROLE; (python object) Role ---- .. autoclass:: Role :member-order: groupwise :members: External Function ----------------- .. autoclass:: Function :member-order: groupwise :members: Function argument ----------------- .. autoclass:: FunctionArgument :member-order: groupwise :members: Dependencies between objects ---------------------------- .. autoclass:: Dependency :member-order: groupwise :members: .. _KInterbasDB: http://www.firebirdsql.org/index.php?op=devel&sub=python .. _Python Database API: http://www.python.org/topics/database/DatabaseAPI-2.0.html