Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hcohP-0003If-GS for pgadmin-hackers@arkaria.postgresql.org; Mon, 17 Jun 2019 10:17:15 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.89) (envelope-from ) id 1hcohN-0008EA-VS for pgadmin-hackers@arkaria.postgresql.org; Mon, 17 Jun 2019 10:17:13 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hcohN-0008E3-8k for pgadmin-hackers@lists.postgresql.org; Mon, 17 Jun 2019 10:17:13 +0000 Received: from mail-io1-xd42.google.com ([2607:f8b0:4864:20::d42]) by makus.postgresql.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_CBC_SHA1:256) (Exim 4.89) (envelope-from ) id 1hcohJ-0001nM-DJ for pgadmin-hackers@postgresql.org; Mon, 17 Jun 2019 10:17:12 +0000 Received: by mail-io1-xd42.google.com with SMTP id u13so20031165iop.0 for ; Mon, 17 Jun 2019 03:17:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pgadmin.org; s=google; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=TaFfH9Ews3o2lxjRMdDwAxAATtE2TguAqnJYArRMdEE=; b=R/3xMUXrB/i9JRoyHxqHT8mk2b5a8xiII89L+08mZ2KCeVAJk0Vo1S0i5W9232wY5G tRNnx5oASAW3i+qUWgrNa31pge2ZT8b1V69fGKC+CK35W9I4L9PGUnhDH1JBZ8zNRWEc GicNhITGoGMnZjtBpfIDUO3J1ZfjSnbrh3xjnoCq3oSHCWM3QqNT2iWL7pnJdMKwTS7v FtNyrUxN9cTgRU5h4Sf9S7w1SneBOj0Ck9aJ2L0FV8IWRi09cC0uVP2YLcXbHe4ooyl2 FOp4vA7U3uaCHovXlm1x2HuRko5Vs6f22TsahGCKC+ecN73WfeHk5/CYRBymNWmUPNBt xHAQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=TaFfH9Ews3o2lxjRMdDwAxAATtE2TguAqnJYArRMdEE=; b=VgoWIoVKgrhuzCgveha4KF7KSAFkVef6JmTkurKzp+K7otW7ZPAWKRS78aDkP7Xk5Q kANmFXNovMo9h+WRiphTO8MLO7wJsJoSMXQNi/KcuWyY/hSEmhqce+IHWWyzP46ImkWn rRUKEQ2VHOa2Vg/r7DfYERT1rqXvScQrkcfSZ2krIIh45rTkOJHvz6sRYOcAXoNFux6M HfmKzKSkSXstRnXsS988capukb4fTgF7z+awRfI8XEsGWDR+hd1coHUxFr0q7qSPwc1d MloBIKH44s4c8AEYGKh2e08CJlCuFoWDeIYuRKBkOWzNJ5mx10zCw0aM+dHycQpUZqtU Ozig== X-Gm-Message-State: APjAAAUuG8GVMNtAvxZ0fxEmTYzy5Mv6a8asPCGF2TVlmn6aendxyYNn NeEfNv8DSHUuF8xhQzOJjyTUfkUssv51QygqbWr13Q== X-Google-Smtp-Source: APXvYqyjx1rqByltRkFUemr6iteH7F2EJJ2tAw2mfqxrQ+DJ5/HWwTmtuwouHjI8ZH/Kl2ehVXa0tMFTpA9bXujA4Ok= X-Received: by 2002:a02:ce52:: with SMTP id y18mr77621799jar.78.1560766628077; Mon, 17 Jun 2019 03:17:08 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: From: Dave Page Date: Mon, 17 Jun 2019 11:16:56 +0100 Message-ID: Subject: Re: [GSoC][Patch] Automatic Mode Detection V1 To: Yosry Muhammad Cc: pgadmin-hackers Content-Type: multipart/alternative; boundary="00000000000071b68e058b824c9a" List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Precedence: bulk --00000000000071b68e058b824c9a Content-Type: text/plain; charset="UTF-8" Hi On Sun, Jun 16, 2019 at 3:10 PM Yosry Muhammad wrote: > This is a patch fixing a problem with the above patch that happened when: > - primary key columns are renamed. > - other columns are renamed to be like primary key columns. > > This problem happened mainly because the primary keys are identified in > the front-end by their names. This can be handled in a better way in a > future update where columns that are primary keys are identified by the > backend and sent to the frontend instead. > Also, renamed columns can be handled better by making them read-only in a > future update (now they are editable but they cannot be updated as a column > with the new name does not exist - it produces an error message to the > user). > Seems like a fairly low-impact problem. Most people probably don't rename columns whilst they're editing data in the same table. That said, if it's not overly invasive or complex, I see no reason not to fix it. > > On Sat, Jun 15, 2019 at 8:48 AM Yosry Muhammad wrote: > >> Dear all, >> >> This is my first patch of my GSoC project, query tool automatic mode >> detection. >> >> In this patch, the initial (basic) version of the project is implemented. >> In this version, query resultsets are updatable if and only if: >> - All the columns belong to a single table >> - No duplicate columns are available >> - All the primary keys of the table are available >> >> Inserts, updates and deletes work automatically when the resultset is >> updatable. >> > Hmm, I wonder if I under-estimated the complexity of this task! There is more work to do of course, but it almost looks like you've done the hard part. Still, there are plenty of other related things that can be improved along the way. > >> The 'save' button in the query tool works automatically to save the >> changes in the resultset if the query is the updatable, and saves the query >> to a file otherwise. The 'save as' button stays as is. >> > Yeah, I think we'll have to have a second Save button. The current one would save the query text, whilst the new one would save changes to the data. Do you want me to ask our design guy for an icon? > >> I will work on improving and adding features to this version throughout >> my work during the summer according to what has the highest priorities >> (supporting duplicate columns or columns produced by functions or >> aggregations as read-only columns in the results seems like a good next >> move). >> > I think handling read-only columns is most important, then duplicates. > Please give me your feedback of the changes I made, and any hints or >> comments that will improve my code in any aspect. >> > Well the first problem is that it doesn't actually work for me. This is what I get when running a simple "select * from pem.probe" (where pem.probe is a table with primary key and a few columns - see below) on a PG11 system (with both of your patches applied): 2019-06-17 10:56:44,610: SQL flask.app: Execute (void) for server #5 - CONN:3976967 (Query-id: 2391511): BEGIN; 2019-06-17 10:56:44,610: SQL flask.app: Execute (async) for server #5 - CONN:3976967 (Query-id: 5707996): select * from pem.probe 2019-06-17 10:56:44,614: INFO werkzeug: 127.0.0.1 - - [17/Jun/2019 10:56:44] "POST /sqleditor/query_tool/start/3781524 HTTP/1.1" 200 - 2019-06-17 10:56:44,631: SQL flask.app: Polling result for (Query-id: 5707996) 2019-06-17 10:56:44,635: SQL flask.app: Polling result for (Query-id: 5707996) 2019-06-17 10:56:44,639: SQL flask.app: Execute (dict) for server #5 - CONN:3976967 (Query-id: 5976248): SELECT at.attname, ty.typname FROM pg_attribute at LEFT JOIN pg_type ty ON (ty.oid = at.atttypid) WHERE attrelid=17491::oid AND attnum = ANY ( (SELECT con.conkey FROM pg_class rel LEFT OUTER JOIN pg_constraint con ON con.conrelid=rel.oid AND con.contype='p' WHERE rel.relkind IN ('r','s','t', 'p') AND rel.oid = 17491::oid)::oid[]) 2019-06-17 10:56:44,641: ERROR flask.app: 'attnum' Traceback (most recent call last): File "/Users/dpage/.virtualenvs/pgadmin4/lib/python3.7/site-packages/flask/app.py", line 1813, in full_dispatch_request rv = self.dispatch_request() File "/Users/dpage/.virtualenvs/pgadmin4/lib/python3.7/site-packages/flask/app.py", line 1799, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "/Users/dpage/.virtualenvs/pgadmin4/lib/python3.7/site-packages/flask_login/utils.py", line 261, in decorated_view return func(*args, **kwargs) File "/Users/dpage/git/pgadmin4/web/pgadmin/tools/sqleditor/__init__.py", line 462, in poll trans_obj.check_for_updatable_resultset_and_primary_keys() File "/Users/dpage/git/pgadmin4/web/pgadmin/tools/sqleditor/command.py", line 904, in check_for_updatable_resultset_and_primary_keys is_query_resultset_updatable(conn, sql_path) File "/Users/dpage/git/pgadmin4/web/pgadmin/tools/sqleditor/utils/is_query_resultset_updatable.py", line 75, in is_query_resultset_updatable 'column_number': row['attnum'] KeyError: 'attnum' This is the table definition: ======== -- Table: pem.probe -- DROP TABLE pem.probe; CREATE TABLE pem.probe ( id integer NOT NULL DEFAULT nextval('pem.probe_id_seq'::regclass), display_name text COLLATE pg_catalog."default" NOT NULL, internal_name text COLLATE pg_catalog."default" NOT NULL, collection_method character(1) COLLATE pg_catalog."default" NOT NULL, target_type_id integer NOT NULL, applies_to_id integer NOT NULL, agent_capability text COLLATE pg_catalog."default", probe_code text COLLATE pg_catalog."default" NOT NULL, enabled_by_default boolean NOT NULL, default_execution_frequency integer NOT NULL, default_lifetime integer NOT NULL, any_server_version boolean NOT NULL, force_enabled boolean NOT NULL DEFAULT false, probe_key_list character varying[] COLLATE pg_catalog."default" NOT NULL DEFAULT '{}'::character varying[], discard_history boolean NOT NULL DEFAULT false, is_system_probe boolean NOT NULL DEFAULT true, deleted boolean NOT NULL DEFAULT false, deleted_time timestamp with time zone, platform text COLLATE pg_catalog."default", is_chartable boolean NOT NULL DEFAULT true, jstid integer, CONSTRAINT probe_pkey PRIMARY KEY (id), CONSTRAINT probe_applies_to_id_fkey FOREIGN KEY (applies_to_id) REFERENCES pem.probe_target_type (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT probe_purge_jobstep_id_fkey FOREIGN KEY (jstid) REFERENCES pem.jobstep (jstid) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT probe_target_type_id_fkey FOREIGN KEY (target_type_id) REFERENCES pem.probe_target_type (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION, CONSTRAINT probe_collection_method CHECK (collection_method = ANY (ARRAY['b'::bpchar, 's'::bpchar, 'i'::bpchar, 'w'::bpchar])), CONSTRAINT probe_target_type_coherence CHECK (collection_method <> 's'::bpchar OR target_type_id <> 100) ) WITH ( OIDS = FALSE ) TABLESPACE pg_default; ALTER TABLE pem.probe OWNER to postgres; COMMENT ON COLUMN pem.probe.default_lifetime IS 'Default lifetime value in days'; -- Trigger: create_delete_purge_probe_jobstep_trigger -- DROP TRIGGER create_delete_purge_probe_jobstep_trigger ON pem.probe; CREATE TRIGGER create_delete_purge_probe_jobstep_trigger AFTER INSERT OR DELETE ON pem.probe FOR EACH ROW EXECUTE PROCEDURE pem.create_delete_probe_purge_jobstep(); -- Trigger: pem_custom_probe_deleted -- DROP TRIGGER pem_custom_probe_deleted ON pem.probe; CREATE TRIGGER pem_custom_probe_deleted BEFORE UPDATE OF deleted ON pem.probe FOR EACH ROW EXECUTE PROCEDURE pem.custom_probe_deleted(); -- Trigger: probe_preupdate -- DROP TRIGGER probe_preupdate ON pem.probe; CREATE TRIGGER probe_preupdate BEFORE INSERT OR UPDATE ON pem.probe FOR EACH ROW EXECUTE PROCEDURE pem.probe_preupdate(); -- Trigger: update_purge_jobs_on_insert_probe -- DROP TRIGGER update_purge_jobs_on_insert_probe ON pem.probe; CREATE TRIGGER update_purge_jobs_on_insert_probe AFTER INSERT ON pem.probe FOR EACH STATEMENT EXECUTE PROCEDURE pem.run_job_to_update_probe_objects_combo(); -- Trigger: update_purge_jobs_on_update_probe -- DROP TRIGGER update_purge_jobs_on_update_probe ON pem.probe; CREATE TRIGGER update_purge_jobs_on_update_probe AFTER UPDATE OF default_lifetime ON pem.probe FOR EACH ROW EXECUTE PROCEDURE pem.run_job_to_update_probe_objects_combo(); ======== > >> I also have a couple of questions, >> - Should the save button in the query tool work the way I am using it >> now? or should there be a new dedicated button for saving the query to a >> file? >> > See above :-) > >> - What documentations or unit tests should I write? any guidelines here >> would be appreciated. >> > We're aiming to add unit tests to give as much coverage as possible, focussing on Jasmine, Python/API and then feature tests in that order (fast -> slow execution, which is important). So we probably want - one feature test to do basic end-to-end validation - Python/API tests to exercise is_query_resultset_updatable, save_changed_data and anything else that seems relevant. - Jasmine tests to ensure buttons are enabled/disabled as they should be, and that primary key and updatability data is tracked properly (this may not be feasible, but I'd still like it to be investigated and justified if not). We're also a day or two away from committing a new test suite for exercising CRUD operations and the resulting reverse engineered SQL; if we can utilise that to test primary_keys.sql, that'd be good. Once the in-place editing works, we'll need to rip out all the code related to the View/Edit data mode of the query tool. For example, there will be no need to have the Filter/Sort options any more as the user can edit the SQL directly (that one may be controversial - it's probably worth polling the users first). Of course, if they don't want it to be removed, we'll need to re-think how it works as then we'd have a dialogue that tries to edit arbitrary SQL strings. When all that's done, the docs will need an overhaul to make them match the new design. That'll require new screenshots, and some non-trivial changes I suspect. You'll need to review what's there at the moment, and figure out what needs to be updated. It's possible we'll need to talk about structural changes as well, but we can do that nearer the time. -- Dave Page Blog: http://pgsnake.blogspot.com Twitter: @pgsnake EnterpriseDB UK: http://www.enterprisedb.com The Enterprise PostgreSQL Company --00000000000071b68e058b824c9a Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Hi

On Sun, Jun 16, 2019 at 3:10 PM Yosry Muhammad <= yosrym93@gmail.com> wrote:
=
This is a patch fixing a problem with the above patch that happened when= :
- primary key columns are renamed.
- other colum= ns are renamed to be like primary key columns.

This problem happened mainly because the primary keys are identified in t= he front-end by their names. This can be handled in a better way in a futur= e update where columns that are primary keys are identified by the backend = and sent to the frontend instead.
Also, renamed columns can = be handled better by making them read-only in a future update (now they are= editable but they cannot be updated as a column with the new name does not= exist - it produces an error message to the user).

Seems like a fairly low-impact problem. Most people pr= obably don't rename columns whilst they're editing data in the same= table. That said, if it's not overly invasive or complex, I see no rea= son not to fix it.
=C2=A0

On Sat, Jun 15, 2019 at 8:48 AM Yosry Muhammad <yosrym93@gmail.com> wrote:=
Dear all,

This is my first patch of my GSoC= project, query tool automatic mode detection.

In = this patch, the initial (basic) version of the project is implemented. In t= his version, query resultsets are updatable if and only if:
- All= the columns belong to a single table
- No duplicate columns are = available
- All the primary keys of the table are available
=

Inserts, updates and deletes work automatically when th= e resultset is updatable.

Hmm, I wonder if I under-estimated the complexity of this= task! There is more work to do of course, but it almost looks like you'= ;ve done the hard part. Still, there are plenty of other related things tha= t can be improved along the way.
=C2=A0

The 'save' button in the query tool works automatically to sa= ve the changes in the resultset if the query is the updatable, and saves th= e query to a file otherwise. The 'save as' button stays as is.
<= /div>

Yeah, I thin= k we'll have to have a second Save button. The current one would save t= he query text, whilst the new one would save changes to the data.

Do you want me to ask our design guy for an icon?
=C2=A0

I will work on improving and adding= features to this version throughout my work during the summer according to= what has the highest priorities (supporting duplicate columns or columns p= roduced by functions or aggregations as read-only columns in the results se= ems like a good next move).

I think handling read-only columns is most important, then = duplicates.
=C2=A0
Please give me your feedback of the chan= ges I made, and any hints or comments that will improve my code in any aspe= ct.

Well the= first problem is that it doesn't actually work for me. This is what I = get when running a simple "select * from pem.probe" (where pem.pr= obe is a table with primary key and a few columns - see below) on a PG11 sy= stem (with both of your patches applied):

2019-06-= 17 10:56:44,610: SQL flask.app: Execute (void) for server #5 - CONN:3976967= (Query-id: 2391511):
BEGIN;
2019-06-17 10:56:44,610: SQL flask.app: = Execute (async) for server #5 - CONN:3976967 (Query-id: 5707996):
select= * from pem.probe
2019-06-17 10:56:44,614: INFO werkzeug: 127.0.0.1 - - = [17/Jun/2019 10:56:44] "POST /sqleditor/query_tool/start/3781524 HTTP/= 1.1" 200 -
2019-06-17 10:56:44,631: SQL flask.app: Polling result f= or (Query-id: 5707996)
2019-06-17 10:56:44,635: SQL flask.app: Polling r= esult for (Query-id: 5707996)
2019-06-17 10:56:44,639: SQL flask.app: Ex= ecute (dict) for server #5 - CONN:3976967 (Query-id: 5976248):
SELECT at= .attname, ty.typname
FROM pg_attribute at LEFT JOIN pg_type ty ON (ty.oi= d =3D at.atttypid)
WHERE attrelid=3D17491::oid AND attnum =3D ANY (
= =C2=A0 =C2=A0 (SELECT con.conkey FROM pg_class rel LEFT OUTER JOIN pg_const= raint con ON con.conrelid=3Drel.oid
=C2=A0 =C2=A0 AND con.contype=3D'= ;p' WHERE rel.relkind IN ('r','s','t', 'p&#= 39;) AND rel.oid =3D 17491::oid)::oid[])

2019-06-17 10:56:44,641: ER= ROR flask.app: 'attnum'
Traceback (most recent call last):
= =C2=A0 File "/Users/dpage/.virtualenvs/pgadmin4/lib/python3.7/site-pac= kages/flask/app.py", line 1813, in full_dispatch_request
=C2=A0 =C2= =A0 rv =3D self.dispatch_request()
=C2=A0 File "/Users/dpage/.virtu= alenvs/pgadmin4/lib/python3.7/site-packages/flask/app.py", line 1799, = in dispatch_request
=C2=A0 =C2=A0 return self.view_functions[rule.endpoi= nt](**req.view_args)
=C2=A0 File "/Users/dpage/.virtualenvs/pgadmin= 4/lib/python3.7/site-packages/flask_login/utils.py", line 261, in deco= rated_view
=C2=A0 =C2=A0 return func(*args, **kwargs)
=C2=A0 File &qu= ot;/Users/dpage/git/pgadmin4/web/pgadmin/tools/sqleditor/__init__.py",= line 462, in poll
=C2=A0 =C2=A0 trans_obj.check_for_updatable_resultset= _and_primary_keys()
=C2=A0 File "/Users/dpage/git/pgadmin4/web/pgad= min/tools/sqleditor/command.py", line 904, in check_for_updatable_resu= ltset_and_primary_keys
=C2=A0 =C2=A0 is_query_resultset_updatable(conn, = sql_path)
=C2=A0 File "/Users/dpage/git/pgadmin4/web/pgadmin/tools/= sqleditor/utils/is_query_resultset_updatable.py", line 75, in is_query= _resultset_updatable
=C2=A0 =C2=A0 'column_number': row['att= num']
KeyError: 'attnum'


=
This is the table definition:

=3D=3D=3D=3D=3D= =3D=3D=3D
-- Table: pem.probe

-- DROP TABLE pem.probe;=

CREATE TABLE pem.probe
(
=C2=A0 =C2=A0 id integer NOT NULL DE= FAULT nextval('pem.probe_id_seq'::regclass),
=C2=A0 =C2=A0 displ= ay_name text COLLATE pg_catalog."default" NOT NULL,
=C2=A0 =C2= =A0 internal_name text COLLATE pg_catalog."default" NOT NULL,
= =C2=A0 =C2=A0 collection_method character(1) COLLATE pg_catalog."defau= lt" NOT NULL,
=C2=A0 =C2=A0 target_type_id integer NOT NULL,
=C2= =A0 =C2=A0 applies_to_id integer NOT NULL,
=C2=A0 =C2=A0 agent_capabilit= y text COLLATE pg_catalog."default",
=C2=A0 =C2=A0 probe_code = text COLLATE pg_catalog."default" NOT NULL,
=C2=A0 =C2=A0 enab= led_by_default boolean NOT NULL,
=C2=A0 =C2=A0 default_execution_frequen= cy integer NOT NULL,
=C2=A0 =C2=A0 default_lifetime integer NOT NULL,=C2=A0 =C2=A0 any_server_version boolean NOT NULL,
=C2=A0 =C2=A0 force_= enabled boolean NOT NULL DEFAULT false,
=C2=A0 =C2=A0 probe_key_list cha= racter varying[] COLLATE pg_catalog."default" NOT NULL DEFAULT &#= 39;{}'::character varying[],
=C2=A0 =C2=A0 discard_history boolean N= OT NULL DEFAULT false,
=C2=A0 =C2=A0 is_system_probe boolean NOT NULL DE= FAULT true,
=C2=A0 =C2=A0 deleted boolean NOT NULL DEFAULT false,
=C2= =A0 =C2=A0 deleted_time timestamp with time zone,
=C2=A0 =C2=A0 platform= text COLLATE pg_catalog."default",
=C2=A0 =C2=A0 is_chartable= boolean NOT NULL DEFAULT true,
=C2=A0 =C2=A0 jstid integer,
=C2=A0 = =C2=A0 CONSTRAINT probe_pkey PRIMARY KEY (id),
=C2=A0 =C2=A0 CONSTRAINT = probe_applies_to_id_fkey FOREIGN KEY (applies_to_id)
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 REFERENCES pem.probe_target_type (id) MATCH SIMPLE
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 ON UPDATE NO ACTION
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ON DEL= ETE NO ACTION,
=C2=A0 =C2=A0 CONSTRAINT probe_purge_jobstep_id_fkey FORE= IGN KEY (jstid)
=C2=A0 =C2=A0 =C2=A0 =C2=A0 REFERENCES pem.jobstep (jsti= d) MATCH SIMPLE
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ON UPDATE NO ACTION
=C2= =A0 =C2=A0 =C2=A0 =C2=A0 ON DELETE NO ACTION,
=C2=A0 =C2=A0 CONSTRAINT p= robe_target_type_id_fkey FOREIGN KEY (target_type_id)
=C2=A0 =C2=A0 =C2= =A0 =C2=A0 REFERENCES pem.probe_target_type (id) MATCH SIMPLE
=C2=A0 =C2= =A0 =C2=A0 =C2=A0 ON UPDATE NO ACTION
=C2=A0 =C2=A0 =C2=A0 =C2=A0 ON DEL= ETE NO ACTION,
=C2=A0 =C2=A0 CONSTRAINT probe_collection_method CHECK (c= ollection_method =3D ANY (ARRAY['b'::bpchar, 's'::bpchar, &= #39;i'::bpchar, 'w'::bpchar])),
=C2=A0 =C2=A0 CONSTRAINT pro= be_target_type_coherence CHECK (collection_method <> 's'::bpc= har OR target_type_id <> 100)
)
WITH (
=C2=A0 =C2=A0 OIDS = =3D FALSE
)
TABLESPACE pg_default;

ALTER TABLE pem.probe
= =C2=A0 =C2=A0 OWNER to postgres;

COMMENT ON COLUMN pem.probe.default= _lifetime
=C2=A0 =C2=A0 IS 'Default lifetime value in days';
=
-- Trigger: create_delete_purge_probe_jobstep_trigger

-- DROP TR= IGGER create_delete_purge_probe_jobstep_trigger ON pem.probe;

CREATE= TRIGGER create_delete_purge_probe_jobstep_trigger
=C2=A0 =C2=A0 AFTER I= NSERT OR DELETE
=C2=A0 =C2=A0 ON pem.probe
=C2=A0 =C2=A0 FOR EACH ROW=
=C2=A0 =C2=A0 EXECUTE PROCEDURE pem.create_delete_probe_purge_jobstep()= ;

-- Trigger: pem_custom_probe_deleted

-- DROP TRIGGER pem_cu= stom_probe_deleted ON pem.probe;

CREATE TRIGGER pem_custom_probe_del= eted
=C2=A0 =C2=A0 BEFORE UPDATE OF deleted
=C2=A0 =C2=A0 ON pem.prob= e
=C2=A0 =C2=A0 FOR EACH ROW
=C2=A0 =C2=A0 EXECUTE PROCEDURE pem.cust= om_probe_deleted();

-- Trigger: probe_preupdate

-- DROP TRIGG= ER probe_preupdate ON pem.probe;

CREATE TRIGGER probe_preupdate
= =C2=A0 =C2=A0 BEFORE INSERT OR UPDATE
=C2=A0 =C2=A0 ON pem.probe
=C2= =A0 =C2=A0 FOR EACH ROW
=C2=A0 =C2=A0 EXECUTE PROCEDURE pem.probe_preupd= ate();

-- Trigger: update_purge_jobs_on_insert_probe

-- DROP = TRIGGER update_purge_jobs_on_insert_probe ON pem.probe;

CREATE TRIGG= ER update_purge_jobs_on_insert_probe
=C2=A0 =C2=A0 AFTER INSERT
=C2= =A0 =C2=A0 ON pem.probe
=C2=A0 =C2=A0 FOR EACH STATEMENT
=C2=A0 =C2= =A0 EXECUTE PROCEDURE pem.run_job_to_update_probe_objects_combo();

-= - Trigger: update_purge_jobs_on_update_probe

-- DROP TRIGGER update_= purge_jobs_on_update_probe ON pem.probe;

CREATE TRIGGER update_purge= _jobs_on_update_probe
=C2=A0 =C2=A0 AFTER UPDATE OF default_lifetime
= =C2=A0 =C2=A0 ON pem.probe
=C2=A0 =C2=A0 FOR EACH ROW
=C2=A0 =C2=A0 E= XECUTE PROCEDURE pem.run_job_to_update_probe_objects_combo();
=3D= =3D=3D=3D=3D=3D=3D=3D
=C2=A0

I also have a cou= ple of questions,
- Should the save button in the query tool work= the way I am using it now? or should there be a new dedicated button for s= aving the query to a file?
=
See above :-)
=C2=A0

- What doc= umentations or unit tests should I write? any guidelines here would be appr= eciated.

We&= #39;re aiming to add unit tests to give as much coverage as possible, focus= sing on Jasmine, Python/API and then feature tests in that order (fast ->= ; slow execution, which is important). So we probably want=C2=A0
=
- one feature test to do basic end-to-end validation
- Python/API tests to exercise=C2=A0is_query_resultset_updatable, save_c= hanged_data and anything else that seems relevant.
- Jasmine test= s to ensure buttons are enabled/disabled as they should be, and that primar= y key and updatability data is tracked properly (this may not be feasible, = but I'd still like it to be investigated and justified if not).

We're also a day or two away from committing a new te= st suite for exercising CRUD operations and the resulting reverse engineere= d SQL; if we can utilise that to test primary_keys.sql, that'd be good.=

Once the in-place editing works, we'll need t= o rip out all the code related to the View/Edit data mode of the query tool= . For example, there will be no need to have the Filter/Sort options any mo= re as the user can edit the SQL directly (that one may be controversial - i= t's probably worth polling the users first). Of course, if they don'= ;t want it to be removed, we'll need to re-think how it works as then w= e'd have a dialogue that tries to edit arbitrary SQL strings.

When all that's done, the docs will need an overhaul to= make them match the new design. That'll require new screenshots, and s= ome non-trivial changes I suspect. You'll need to review what's the= re at the moment, and figure out what needs to be updated. It's possibl= e we'll need to talk about structural changes as well, but we can do th= at nearer the time.
=C2=A0
--
Dave Page
Blog: http://pgsnake.blogspot.com
Twitter: @pgsna= ke

EnterpriseDB UK: http://www.enterprisedb.com
The Enterprise PostgreSQL Co= mpany
--00000000000071b68e058b824c9a--