How to make a TW3EditBox accept Floating point values - smart-mobile-studio

When TW3EditBox control's InputType = iNumber, the only public members for controlling the type of Number (Integer vs Float) are:
public
procedure setMin(const aValue: Variant); virtual;
procedure setMax(const aValue: Variant); virtual;
procedure setRange(const aValue: Variant); virtual;
However, there is nothing for the Step, if one wants to create Edit Boxes that take floating points
e.g.
public
procedure setStep(const aValue: Variant); virtual;
How do you do floating point values in edit boxes?

You can set the step like this:
w3_setAttrib(NumEdit.Handle, 'step', 0.5);

Related

Oracle SQL: create procedure that takes a table as input

I would like to create a procedure that takes a table (T in the example) as an input.
However I don't want to provide the table name as a char and do something 'dynamic' like
begin
execute immediate ('delete from '||T||' where ...');
end;
because the actual task I am dealing with involves several inputs to the function and a long query to execute which has a lot of apices... the string to execute becomes really messy and difficult to debug.
I would like to have something simple as the following (which works):
CREATE or replace PROCEDURE fun (x NUMBER) AS
BEGIN
DELETE FROM MyTable WHERE MyTable.var= fun.x;
END;
/
However giving the table as an input to the procedure (I need to do it because otherwise, in the real task, I would need to change the "T" in a lot of occurrences within the procedure) does not work:
CREATE or replace PROCEDURE fun (x NUMBER, T table) AS
BEGIN
DELETE FROM T WHERE T.var= fun.x;
END;
/
Errors for PROCEDURE FUN
----------------------------
L:1 C:32 PLS-00103: Encountered the symbol "TABLE" when expecting one of the following:
in out <an identifier> <a double-quoted delimited-identifier>
... long double ref char time timestamp interval date binary
national character nchar
The symbol "<an identifier> was inserted before "TABLE" to continue.
1 statement failed.
Is it possible to have something close to what I want?
I have devised a tornaround which is surely not elegant but, according to the comments, appears to be the only way to avoid large pieces of dynamic "execute immediate" code.
CREATE or replace PROCEDURE fun (T_in char, T_out char, x number)
as
BEGIN
/* I create a temporary replica with a view */
execute immediate 'create or replace view tempview as select * from '||T_in;
/* DO STUFF, for example: */
delete from tempview where ente_segn = fun.x;
/* Save the results in a new table */
execute immediate 'create or replace view '||T_out||' as select * from tempview';
END;
/

How return a list in PL/SQL

I'm trying to return a list of char in a function PL/SQL with Oracle 11, but without succes.
I've got a few difficulties for understand their running...
For example, i have this code created for test:
create type test is table of varchar(500);
/
CREATE OR REPLACE FUNCTION test2 (id INT)
RETURN test
is
tt_t test;
BEGIN
SELECT descriptifSpecifique INTO tt_t(1)
FROM DECOMPOSE
where idRecette=id
AND idEtape=2;
SELECT descriptifSpecifique INTO tt_t(2)
FROM DECOMPOSE
where idRecette=id
AND idEtape=3;
RETURN tt_t;
END;
/
show errors function test;
The fonction is created without compilation's problem, but at the execution, I have this message: ORA-06531: Reference to uninitialized collection.
Also, how can I return a type (with a varchar and a int generated by a select for example) IN PL/SQL. Because when I try to make a declaration of type with RECORD, and RETURN this type, I have compilation's problem because type is not declarated...
Thank you
You are basically doing it correctly. But you need to EXTEND your collection before you put new elements into it.
Personally, I prefer to BULK COLLECT into the collection to avoid having to EXTEND and manage the entries at each index. Like this (code untested):
CREATE OR REPLACE FUNCTION test2 (id INT)
RETURN test
is
tt_t test;
BEGIN
SELECT descriptifSpecifique
BULK COLLECT INTO tt_t
FROM DECOMPOSE
where idRecette=id
AND idEtape IN (2,3)
ORDER BY idEtape;
RETURN tt_t;
END;
/
To return a TYPE having multiple columns, you need to create two types: an OBJECT type and a TABLE OF that object type.
Like so,
CREATE TYPE test_rec IS OBJECT ( a_varchar VARCHAR2(500), a_number NUMBER);
CREATE TYPE test_tbl IS TABLE OF test_rec;
Then, you can modify your function accordingly:
CREATE OR REPLACE FUNCTION test2 (id INT)
RETURN test_tbl
is
tt_t test_tbl;
BEGIN
SELECT test_rec(idEtape, descriptifSpecifique)
BULK COLLECT INTO tt_t
FROM DECOMPOSE
where idRecette=id
AND idEtape IN (2,3)
ORDER BY idEtape;
RETURN tt_t;
END;
/

Algebraic Data Types in Postgres

Is it possible to create an Algebraic Data Type in Postgres and then use it as a column type?
For example:
CREATE TYPE hoofed AS ENUM('horse', 'goat');
CREATE TYPE monkey AS ENUM('chimp','macaque');
CREATE TYPE ANIMAL AS ENUM(hoofed, monkey);
This fails with:
syntax error at or near "hoofed"
LINE 1: CREATE TYPE ANIMAL AS ENUM(hoofed, monkey);
Is it possible to do something like this?
Ultimately what I would then like to be able to do is something like so:
CREATE TABLE zoo (
a ANIMAL,
name text
);
INSERT INTO zoo(a, name) VALUES('horse', 'bob');
INSERT INTO zoo(a, name) VALUES('macaque', 'jimmy');
And for both of the records to be independently valid.
EDIT: #Abihabi87's response below does allow me to create, in effect, a product type, but it still does not allow me to create a union type as desired.
You cant create type enum from others enum type:
you can create ANIMAL that like:
CREATE TYPE ANIMAL AS (h hoofed,m monkey);
Example in use:
CREATE TABLE your_table
(
a ANIMAL
);
INSERT INTO your_table(a) select (select ('horse','macaque')::ANIMAL);
With ENUM types, you cannot achieve dynamic type composition/union. However, with DOMAIN types, you could achieve something similar:
create function valid_any_domain(anyelement, variadic regtype[])
returns boolean
language plpgsql
immutable
as $func$
declare
t regtype;
begin
foreach t in array $2 loop
begin
execute format('select $1::%s', t) using $1;
exception
when not_null_violation or check_violation then
continue;
end;
return true;
end loop;
return false;
end;
$func$;
create domain hoofed as text
check (value in ('horse', 'goat'));
create domain monkey as text
check (value in ('chimp','macaque'));
create domain animal as text
check (valid_any_domain(value, 'hoofed', 'monkey'));
Changing the base types will dynamically change the composite/union type too, but still requires a manual constraint validation (especially, when some value(s) are removed from the valid spectrum):
alter domain hoofed drop constraint hoofed_check;
alter domain hoofed add check (value in ('horse', 'goat', 'zebra'));
alter domain animal validate constraint animal_check;
http://rextester.com/MBVC62095
Note: however, with DOMAIN types, you will lose an ENUM property: the custom ordering. DOMAINs will always use the underlying type's ordering.
Use the function:
create or replace function create_enum(name, variadic regtype[])
returns void language plpgsql as $$
begin
execute format(
'create type %I as enum(%s)',
$1,
string_agg(quote_literal(enumlabel), ',' order by enumtypid, enumsortorder))
from pg_enum
where enumtypid = any($2);
end $$;
Pass the name of a new type and a list of enum types as arguments:
select create_enum('animal', 'hoofed', 'monkey');
select enum_range(null::animal) as animal;
animal
----------------------------
{horse,goat,chimp,macaque}
(1 row)
Effectively you are trying to merge two enum types.
There are some open questions:
Can there be duplicate strings?
Is the design supposed to be static (changes to enum type hoofed do not change type animal later) or dynamic (the opposite).
Merge exactly two enum types or more?
Since the order of elements is significant, what is the order of elements in animal supposed to be?
Is this a one-time operation or intended for repeated use?
Assuming no duplicates, static design, two enum types, existing order of elements as appended and one-time operation.
You can use the built-in enum support function enum_range(anyenum) to get an array of all elements for a given enum type.
DO
$$
BEGIN
EXECUTE (
SELECT 'CREATE TYPE animal AS ENUM ('
|| array_to_string(enum_range(null::hoofed)::text[]
|| enum_range(null::monkey)::text[], ''',''')
|| ''')'
);
END
$$;

Best way to create a stored procedure that takes about 30 columns as arguments ? in postgres

What would be the best way to create a stored procedure to apply changes to the database that has about 30 arguments (columns) to be changed?
Right now I'm playing on creating a huge insert query inside the stored procedure that list all the arguments that are passed by the user. Is that the only way or is there a better way for stored procedures this big?
Example:
CREATE OR REPLACE FUNCTION "applyntunesettings"(val1,val2....val30)
RETURNS void AS
BEGIN
INSERT INTO calibrationstable (col1,col2........col20) Values (val1,val2.....val20);
INSERT INTO devicestable (col1,col2,.....col10) values (val21,val22,....val30);
END
Sometimes, row type variables can be convenient. Assuming the tables are "calibrations" and "devices" we can write:
CREATE OR REPLACE FUNCTION applyntunesettings (
_device_name TEXT
, _some_value TEXT
, _other_value TEXT
-- and so on
) RETURNS void AS $$
DECLARE
_calibration calibrations;
_device devices;
BEGIN
_device.name := _device_name;
INSERT INTO devices SELECT _device.*;
_calibration.some_value := _some_value;
_calibration.other_value := _other_value;
INSERT INTO calibrations SELECT _calibration.*;
END $$ LANGUAGE plpgsql;

Postgresql trigger function with parameters

I want to create a trigger on a table called takes in postgresql to update a value in another table called student
I'm trying to do it in the following way. But I'm getting an error that there is syntax error near "OLD". I don't understand whats wrong with this. This is my code:
CREATE OR REPLACE FUNCTION upd8_cred_func
(id1 VARCHAR, gr1 VARCHAR,id2 VARCHAR, gr2 VARCHAR)
RETURNS void AS $$
BEGIN
IF (id1=id2 and gr1 is null and gr2 is not null) THEN
update student set tot_cred = tot_cred + 6 where id = id1;
END IF;
RETURN;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER upd8_cred
AFTER UPDATE ON takes
FOR EACH ROW
EXECUTE PROCEDURE upd8_cred_func(OLD.id,OLD.grade,NEW.id,NEW.grade);
You do not need to pass the NEW and OLD as parameters to the trigger function. They are automagically available there:
http://www.postgresql.org/docs/9.1/interactive/trigger-definition.html :
The trigger function must be declared as a function taking no arguments and returning type trigger. (The trigger function receives its input through a specially-passed TriggerData structure, not in the form of ordinary function arguments.)
About the records passed to the trigger procedure, please see http://www.postgresql.org/docs/9.1/interactive/plpgsql-trigger.html :
When a PL/pgSQL function is called as a trigger, several special variables are created automatically in the top-level block. They are: [...] NEW, [...] OLD [...]
As SeldomNeedy pointed in the comment below, you can still pass and use parameters to the trigger function. You declare the function as taking no parameters, but when defining the trigger (by CREATE TRIGGER), you may add some.
They will be available for the trigger as TG_NARG (the number of such parameters), and TG_ARGV[] (an array of text values).
As Greg stated, trigger functions can take arguments, but the functions themselves cannot have declared parameters. Here's a simple example in plpgsql:
CREATE TABLE my_table ( ID SERIAL PRIMARY KEY ); -- onelined for compactness
CREATE OR REPLACE FUNCTION raise_a_notice() RETURNS TRIGGER AS
$$
DECLARE
arg TEXT;
BEGIN
FOREACH arg IN ARRAY TG_ARGV LOOP
RAISE NOTICE 'Why would you pass in ''%''?',arg;
END LOOP;
RETURN NEW; -- in plpgsql you must return OLD, NEW, or another record of table's type
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER no_inserts_without_notices BEFORE INSERT ON my_table
FOR EACH ROW EXECUTE PROCEDURE raise_a_notice('spoiled fish','stunned parrots');
INSERT INTO my_table DEFAULT VALUES;
-- the above kicks out the following:
--
-- NOTICE: Why would you pass in 'spoiled fish'?
-- NOTICE: Why would you pass in 'stunned parrots'?
--
There are a few other goodies such as TG_NARGS (to know how many args you got without looping through them) discussed in the docs. There's also information there about how to get the name of the triggering table in case you have mostly-but-not-quite-shared logic for one trigger-function that spans a number of tables.
The trigger function can have parameters, but, you can't have those parameters passed like a normal function (e.g. arguments in the function definition). You can get the same result... In python you get access to the OLD and NEW data as the answer above describes. For example, I can use TD['new']['column_name'] in python to reference the new data for column_name. You also have access to the special variable TD['args']. So, if you like:
create function te() returns trigger language plpython2u as $function$
plpy.log("argument passed 1:%s 2:%s" %(TD['args'][0], TD['args'][1], ))
$function$
create constraint trigger ta after update of ttable
for each for execute procedure te('myarg1','myarg2');
Granted, these arguments are static, but, they are useful when calling a common trigger function from multiple trigger declarations. I am pretty sure that the same variables are available for other stored procedure languages. (sorry if the code doesn't work verbatim, but, I do practice this technique, so I know you can pass arguments!).