• Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

AltME groups: search

Help · search scripts · search articles · search mailing list

results summary

worldhits
r4wp56
r3wp608
total:664

results window for this page: [start: 101 end: 200]

world-name: r3wp

Group: All ... except covered in other channels [web-public]
Geomol:
5-Jan-2005
About 50k of REBOL/Core source. Build as a relative level and an 
index level on top of that - top-most a full relational DB. I've 
also started a SQL interface, but I'm not sure, if I wanna finish 
that part. :-)
Group: !Uniserve ... Creating Uniserve processes [web-public]
Graham:
11-Mar-2005
if anyone uses, mysql, they can rewrite the sql statements.
MikeL:
1-Sep-2006
When I can get that simple part working then I want to add Make-Doc, 
my-sql-protocol and Andrew's ML dialect as services so I can get 
some leverage from these.
Group: Tech News ... Interesting technology [web-public]
Terry:
4-Mar-2006
  MySQL 5.0 Adds Features for Enterprise Developers and DBAs
by Ken 
  North

Baseball legend Satchel Paige is famous for having said 

Don't look back, something might be gaining on you." Companies selling 
a commercial SQL database management system (DBMS) know its MySQL 
that's gaining on them. With an already large installed base, MySQL 
is set to attract new users because of the feature set of version 
5.0. It includes capabilities for which developers have often turned 
to commercial SQL products.


The purposes for which we use personal, mobile, workgroup, departmental, 
enterprise and web databases are diverse. Application requirements 
are a primary determinant of the capacity and features we need from 
an SQL DBMS. For example, a high-volume transaction processing web 
site places greater demands on a database than a contact list manager 
for laptops and small business servers.


A Web Techniques magazine article, "Web Databases: Fun with Guests 
or Risky Business?" discussed features that characterize an industrial-grade 
SQL DBMS. It explained SQL security and mission-critical databases, 
defined as


    "A database is mission critical if its lack of data integrity has 
    serious consequences, such as causing the loss of customers or even 
    lives."


Maintaining data integrity is implicit -- that's a prime directive 
for a DBMS. The article explained other features that enterprise 
developers look for in an SQL platform:


    ... mission-critical applications require features such as intrinsic 
    security, transaction journaling, concurrency controls and the ability 
    to enforce data integrity constraints. Without those features, you 
    do not have secure, robust databases. Connecting a database to a 
    Web server adds other requirements, such as a multithreaded architecture 
    and the ability to do database backups without taking the server 
    down.


    Freeware and PC DBMSs are suitable for certain classes of applications, 
    but not for high-volume Web sites and mission-critical databases. 
    In any case, don't bet your business, or lives, on such software 
    unless you have the source code and the expertise to understand and 
    repair it.


Since that article appeared in print, improvements to MySQL have 
removed the "not ready for prime time" label. Features described 
in that article are now available to MySQL users:

    * transactions
    * concurrency control, locking, SQL standard isolation levels
    * intrinsic security
    * integrity constraints
    * thread-based memory allocation.

  TII Computer Deals at Dell Home Systems 180x150
	


MySQL uses separate threads to handle TCP/IP and named pipes connections, 
authentication, signaling, alarms and replication. The combination 
of threaded architecture and MySQL clustering provides powerful parallel 
processing capabilities. MySQL can process transactions in parallel 
with separate connections on separate processors using separate threads.
MySQL Milestones


A decade of development has moved MySQL out of the bare-bones DBMS 
category, enlarged its user base, and turned MySQL AB into a profitable 
company. One of the important milestones was integration of the InnoDB 
engine with MySQL 4.0. That upgrade gave MySQL multiple tablespaces, 
tables greater than 4GB and support for transaction processing. Other 
enhancements included OpenGIS spatial data types and hot backups. 
The latter enables a DBA to perform a backup without taking the DBMS 
offline. Hot backup software is available as a commercial add-on 
for databases using the InnoDB storage engine. 


MySQL 5.0, the newest version, is a major milestone. There have been 
enhancements to the tool sets, storage engines, types and metadata. 
 MySQL 5.0 includes features enterprise developers have come to expect 
from commercial SQL products. 

    * capacity for very large databases
    * stored procedures
    * triggers
    * named-updateable views
    * server-side cursors
    * type enhancements
    * standards-compliant metadata (INFORMATION_SCHEMA)
    * XA-style distributed transactions
    * hot backups.


MySQL has a demonstrated capacity for managing very large databases. 
Mytrix, Inc. maintains an extensive collection of Internet statistics 
in a one terabyte (1 TB) data warehouse that contains 20 billion 
rows of data. Sabre Holdings runs the oldest and largest online travel 
reservation system. It replicates 10-60 gigabytes per day from its 
master database to a MySQL server farm. The MySQL databases are used 
to support a shopping application that can accommodate a million 
fare changes per day."
Davide:
1-Apr-2006
After Ruby on rails, Sql on rails. How to make killer web apps: http://sqlonrails.org/screencast
JaimeVargas:
12-May-2006
With abstractions, unit-testing, versioning, environment scoping 
(development, testing, production), autodomentation, portability, 
compatibility (any SQL db here), etc. Rails rocks.
Group: !RebDB ... REBOL Pseudo-Relational Database [web-public]
Ashley:
8-Feb-2006
JOIN differs from SUB-SELECT where you want to aggregate the columns 
of more than one table, so:

	select a.col, b.col from a, b


cannot be refactored as a sub-select. There are two reasons why I 
have not implemented JOINs in RebDB [yet]:

1) Dramatic increase in code complexity

2) You can almost always do it more efficiently in REBOL as you *know* 
the data structures and desired result set *in advance*.


About the only time this does not work well [in RebDB] is where you 
have to pull the contents of more than one table across a network 
to derive a small subset as the result set. So while this SQL would 
not suffer:

	select a.col, b.col from a, b

this might:

	select a.key, b.val from a, b where a.key = b.key

depending on the size of b.
Ashley:
8-Feb-2006
It's called a "Pseudo-Relational Database" for a good reason. ;)


But in answer to Pekr's previous point; *you* can work out *how* 
to do that aggregation more efficiently than the limited AI of most 
RDBMS systems. I've worked at DB2 and Oracle shops where it was mandated 
that all JOINs be performed inline! SQL optimizers are not trivial 
to write, and the meta-data overhead (indexes, statistics, hints, 
etc) required to get them to make the "right" choices are often a 
false economy.
Ashley:
8-Feb-2006
Data structure makes sense, what's the problematic SQL statement? 
(in its simplest form)
Ashley:
8-Feb-2006
Just write the SQL statement as you would in MySQL, etc ... then 
we can see where the issues are.
Pekr:
8-Feb-2006
that was just an example simple schema, but well, I may try to write 
short SQL query from that ;-)
Sunanda:
8-Feb-2006
Not sure if I'm off topic here.....But you can do pretty much everything 
in SQL without using JOIN. Though you may need UNION, subselects 
and WHERE.

Which makes for more portable SQL as JOIN syntax often used vendor-specific 
extensions to the SQL-92 standard.
Pekr:
8-Feb-2006
Yes, that might be possible ... I am not that skilled in SQL yet, 
so maybe it could be done other way ....
Ashley:
8-Feb-2006
Thanks, I'll take a look at it. (Marco's sql-protocol.r is also a 
good read).
Ashley:
9-Feb-2006
Back to Pekr's JOIN problem. First, let's reformat the SQL into something 
more readable:


select o.order-id, o.date, o.amount, o.total, oi.item-id, io.item-price, 
oi.goods-name, c.company-name
from   orders o
,      order-items oi
,      companies c
where  o.order.id = oi.order-id
  and  o.company-id = c.company-id
  and  o.amount > 2000
order by c.company-name, o.order-id, o-item-id
Ashley:
9-Feb-2006
Then break it down into discrete queries and wrap it in some loops:

blk: copy []

foreach [company-id order-id date amount total] sql [

 select [company-id order-id date amount total] from orders where 
 [amount > 2000]
][
	company-name: second sql compose [lookup companies (company-id)]

 foreach [item-id item-price goods-name] sql compose [select * from 
 order-items where (order-id)] [

  insert tail blk reduce [order-id date amount total item-id item-price 
  goods-name company-name]
	]
]

sort/skip/compare blk 8 [8 1 5]
Ashley:
9-Feb-2006
The final [untested] solution is about as efficient as you can get. 
Adding JOIN support to RebDB so it can break the query down into 
similar steps is not a simple task. In all but the most trivial of 
cases you'd be better off coding it yourself.


What might be a good idea is to add something that lets you more 
easily specify the most common JOIN operation - master/detail with 
optional LOV (List Of Values) lookup(s). Your query is a classic 
example of this construct and it accounts for a surprisingly large 
number of queries.


The function would accept two queries, a master query (the orders 
table in your case) and a details query (the order-items table) and 
an optional block of column/LOV-table pairs (that perform substitutions 
such as company-name). The skeleton would look like:


 sql-join [master-query [block!] detail-query [block!] /order /lov 
 [block!] ]  [
		buffer: copy []
		...
		buffer
	]

and would be used as such:

	sql-join/order/lov [

  select [company-id order-id date amount total] from orders where 
  [amount > 2000]
	] [
		select * from order-items where %ID%
	] [8 1 5] [company-id companies]

Would this make things a tad easier?
Pekr:
9-Feb-2006
not sure your sql query rewrite was much clearer, but - your last 
post makes so much sense!
Coccinelle:
9-Feb-2006
Ashley, sql-protocol generates the code used to extract and join 
the data is grouped in 2 functions :
- make-do-select
- make-do-loop

They receive the column list, the table list (a block of table/alias 
pair), the where code to apply and the database (the port).


If you provide these parameters and change the code to invoke RebDB 
fuction to get the data, you will have a basic join implementation 
for RebDB. You can use it and extend it for RebDB, if you want, I 
will be happy if you do so.
Ashley:
11-Feb-2006
Thanks guys, I've had a good look at both implementations and I've 
got ideas from both for a future full JOIN implementation; but at 
the moment my master/detail code has come along nicely. I've now 
enhanced the db-select function to accept statements in these additional 
forms:


 select * from master joins [select * from details where &id] on id

 select * from master joins [select * from details where [all [master-id 
 = &id master-date = &date]] on [id date]


which works exactly like a normal join with the following differences:

	a) It can only join one table to another

 b) Detail columns are always joined to the right of master columns

 c) Table.column prefixes are not supported so all columns in the 
 join must be uniquely named


Apart from that you get all the benefits of db-select (can replace 
* with specific column combinations, order and group by on the final 
result set, etc) *and* it's significantly faster than even the raw 
REBOL code example I gave before (as the SQL is parsed once within 
db-select and all loop sub-selects are done in-line).

I've also implemented “lookups” with the following form:

	select * from table replaces id with name
	select * from table replaces [id-1 id-2] with [table-1 table-2]


which performs a highly optimized db-lookup for each replaced value, 
but has the following restrictions:


 a) The lookup expects lookup tables in the form [id label other-column(s)]
	b) Only single-key lookups are supported
	c) A lookup that fails will replace the column value with none!


I'm now in the process of benchmarking these changes against sqlite 
to see where the bottlenecks (if any) are. Feedback on the design 
decisions is welcome.


While I was doing this, I was once again reminded how cumbersome 
it is to construct SQL statements (not just for RebDB, same goes 
for the other SQL protocols), as the heavy use of 'compose, 'rejoin, 
etc adds noise that reduces legibility. The design goal is to provide 
alternatives to:


 sql compose/deep [select * from table where [all [col1 = (val1) col2 
 = (val2)]]]


so for a start the 'sql function should probably accept a string, 
to allow:

	sql join “select * from “ table


type constructs; but this doesn't make the first example easier. 
So how about the 'sql function accept a block containing a string 
statement followed by a number of substitution variables, as in:


 sql reduce [“select * from table where [all [col1 = &1 col2 = &2]]” 
 val1 val2]


which makes things a bit more readable (and shortens the expression 
if longer word names are used multiple times). So the two questions 
here are:

	a) Is this a good idea?

 b) If so, what substitution character (& % $ @ other) will cause 
 the least conflict with REBOL and/or SQL?
Sunanda:
11-Feb-2006
Traditional with embedded SQL, the technique is to use "host variables" 
which start with a colon:

 sql reduce “select * from table where [all [col1 = :var1 col2 = :var2 
 ]]”
And you'd magically replace :var1 with the value of var1.


Which is almost exactly the behaviour you'd expect from :var1 in 
REBOL too.

If you insist that that host variables always have a space before 
and after, that makes the whole substitution process a fairly simple 
parse operation.
Coccinelle:
13-Feb-2006
sql-protocol don't need these heavy use of 'compose, 'join, 'reduce 
 if you use the dialect. Something like this work :
   var1: "Marco" 
   insert my-db [select * from my-table where name = var1]
   my-result: copy my-db

Another example to ilustrate this :

   insert my-db [select * from my-table where name like rejoin ["*" 
   var1 "*"]]


This is only if you use the dialect to query the database. If you 
use the standard SQL string, you need to compose the query.
Maxim:
9-Mar-2006
wrt simplyfing the use of "noise"  ... why not just call compose/deep 
by default within the 'execute call of the client on ALL sql calls? 
 it could be a global option and IMHO the use of parens within the 
code is quite obvious and is used in many dialects. and its less 
cumbersome than to add the reduce word in your code, a string and 
then variables out of context of the sql statement.
Maxim:
9-Mar-2006
I understand... which is why I noted, it could be an option... cause 
although  substitution variables are closer to SQL,  expression embedding 
within parenthesis is quite familiar in rebol ... 


but in any case, We can all just wrap the rebdb calls within our 
own I guess ;-)
Maxim:
7-Apr-2006
the only drawback is that sql use needs ticks for table names.   
acter using it for a while I actually like this better, cause it 
clearly identifies what is a reserved word and was is an argument, 
within the statements.
GiuseppeC:
13-Dec-2007
Ok, I suppose I will have to learn both. RebDB for very simple projects 
and SQL for large ones. After Christmas I will buy Rebol/Pro and 
when my project will be ready the whole suite.
Michael:
20-Jan-2008
Ashley, what I am doing wrong here? (I'm trying to sum the column 
"distance" below):

SQL> select distance my-table
distance
--------
1
3
7

SQL> select count distance my-table
Count
-----
    3

SQL> select sum distance my-table
script cannot-use
Ashley:
16-Mar-2008
You are correct, with a standard SQL DB a delete or update statement 
without a where clause will affect every row in the table. With RebDB 
you can achieve the same thing by providing a where clause as follows:

	where [rowid > 0]


and for delete operations don't overlook the truncate (or drop) functions.
BrianH:
7-Oct-2008
I think the find clause here might work for you: http://www.dobeash.com/RebDB/sql-guide.html#section-4
Group: SQLite ... C library embeddable DB [web-public].
Ashley:
13-Feb-2006
sqlite3-protocol.r has a minor bug whereby locals/cols are not cleared. 
Fix is to add a "clear cols" at the beginning of the ' sqlite-exec 
func. Two other changes I made to this function were:


1) Changing “SQLITE_TEXT [any [attempt [load val: sqlite3/column_text 
stmt j] val]]” so as REBOL values are returned, and

2) Removing the /only clause from "system/words/insert/only tail 
result col" for those that prefer flat data structures (i.e. non-blocked 
records)

Finally, a simple wrapper makes the whole thing more usable:

context [

	db: none

	set 'open-db func [name [file!]] [
		db: open join sqlite://localhost/ name
	]

	set 'close-db does [
		close db
	]

	set 'describe func ['table [word!]] [

  insert db rejoin ["select type, name, sql from sqlite_master where 
  upper(tbl_name) = '" uppercase form table "' order by rootpage"]
		db/locals/sqlresult
	]

	set 'sql function [arg [string! block!]] [statement] [
		case [
			string? arg [insert db arg]
			string? first arg [
				statement: copy first arg
				repeat i -1 + length? arg [
					replace/all statement join ":" i pick arg i + 1
				]
				insert db statement
			]
		]
		db/locals/sqlresult
	]
]

which lets you do stuff like:

>> open-db %test.db
>> sql "create table t1 (col1 INTEGER, col2 TEXT)"
== []
>> describe t1
== [table t1 "CREATE TABLE t1 (col1 INTEGER, col2 TEXT)"]
>> sql reduce ["insert into t1 values (1,':1')" now/date]
== []
>> sql "select * from t1"
== [1 13-Feb-2006]
>> close-db
Ashley:
13-Feb-2006
I will once they've settled down ... the SQLITE_TEXT change mentioned 
previously should read:

	SQLITE_TEXT [
		val: sqlite3/column_text stmt j
		any [
			all [
				attempt [tmp: load val]
				not block? tmp
				not word? tmp
				tmp
			]
			val
		]
	]


which should correctly handle TEXT with embedded white-space or illegal 
load chars. The context of funcs can also have the following useful 
func added:

	set 'sql-columns does [
		copy db/locals/cols
	]


and should probably 'copy return db/locals/sqlresult in both the 
'sql and 'describe functions.
Pekr:
15-Feb-2006
What I don'T like about sqlite is that 1) it uses binary storage 
and that 2) it uses all-in-one-file aproach. I know it is low level, 
but I prefer directory/one-file-per-db aproach of RebDB kind of cool 
... I can watch/backup small dbs on per file base, not on going into 
sql base, to find out what internally changed ...
Pekr:
16-Feb-2006
I am also used to rebol blocks. Somehow using string mode for constructing 
sql query is one level off for me, but otoh maybe better, because 
with block mode you sometimes don't cover all syntax options or you 
simply has to learn how to use it, whereas with string you simply 
compose default sql query and you can cut and paste examples or queries 
from docs, visual tools, etc.
Ashley:
16-Feb-2006
I've given up on the one table per database idea as the default attachment 
limit is 10 files. On the positive side, the ATTACH command seems 
to work properly under 3.0+ and table names unique to an attached 
database do not have to be prefixed in queries. ;) My 'connect function:

>> help connect
USAGE:
    CONNECT database /create /attach databases /blocked /direct

DESCRIPTION:
     Open a SQLite database.
     CONNECT is a function value.

ARGUMENTS:
     database -- (Type: file url)

REFINEMENTS:
     /create -- Create database if non-existent

     /attach -- Attach up to 10 databases (of type file!) to this connection
         databases -- Database files (Type: block)
     /blocked -- Return each row as a block
     /direct -- Do not mold/load REBOL values

lets you do this:


 connect/attach %/c/app/data/system.db [%/c/app/data/users.db %/c/app/data/reports.db]
	sql "select * from a-system-table"
	sql "select * from a-user-table"
	sql "select * from a-report-table"


which could be quite useful in many situations. The default, however, 
is now one database.


BTW, my rewrite (even after adding a lot more functionality) is about 
twice as fast as the original protocol version.
Pekr:
16-Feb-2006
Ashley - maybe I vote for functions having sql- or sqlite- prefix 
.... sql then could become sql-query .... because ... standalone 
"disconnect" in rebol script is a bit strangely looking .... in rebol 
you can disconnect from many things ... it does not look obvisous 
at first sight .... what do others think?
Pekr:
16-Feb-2006
I would prefer setting /blocked or not, /direct or not, as a result 
fo query, so maybe those refinements should be available with /sql 
function instead?
Ashley:
17-Feb-2006
Bumped the version to 0.1.2 with three enhancements:

1) Automatic NULL -> none! conversion (and vice versa)

2) 'sql now handles a SQLITE_BUSY return code by retrying the failing 
sqlite3_step 5 times at one second intervals

3) About value (number of retries) can be set with a new connect/timeout 
refinement
sqlab:
17-Feb-2006
It seems you want cursors.

Then you can separate preparing of an sql statement and fetching 
from the cursor.

This would allow to reset an already compiled statement and to redo 
 do it without a new compilation.
Or even to cache compiled statements as Caché does it.
Ashley:
17-Feb-2006
1) why did you name somehow not traditionally functions as connect 
and disconnect?


open and close are already taken and I wanted to avoid pathing (sqlite/open) 
or prefixes (sqlite-open) as the number of words added to the global 
context is relatively few and I wanted them to be meaningful words 
in their own right (same reason why VID doesn't have vid-layout, 
vid-center-face, etc). Connect and disconnect are the commands used 
to login/logout of another user in many databases; so while the context 
is not strictly correct, they are recognisable DB words.

2) why can't we support multiple name-spaces?


You can via the connect/attach refinement (and this lets you transparently 
reference tables across multiple "databases"). Why would you want 
to concurrently access multiple databases that are *not* related 
to each other in any way?

3) can we have opened only one db at a time?


Yes, bar /attach as above. The benefit of this approach is that you 
minimise the number of file locks a single process obtains, and you 
don't have to track state information (i.e. you don't need to tell 
'sql which DB you are referring to).


4) Would it also be possible to extend e.g. 'headings to return non-string 
 values?

No, as it may contain strings like "count(*)"

5) don't agree with exposing functions as you did


I tend to write CONNECT, SQL, etc in upper-case so db references 
embedded in my code stand out. Come up with a better naming scheme 
that everyone likes though and I'll adopt it. ;)
Ashley:
17-Feb-2006
you used db-open even for RebDB

 ... that's because it needed to define about 20 low-level SQL statement 
 functions like 'select, 'delete, ''show, 'close, 'insert, etc that 
 conflicted with existing REBOL words and could not be easily renamed 
 (folks expect a SELECT statement, an UPDATE statement, etc or something 
 that resembles it). With the SQLite driver, all these statements 
 are handled by the SQLite library itself so we only need to provide 
 a few high-level accessor functions like SQL and DESCRIBE; these 
 types of words don't conflict with REBOL's lower-level atomic action 
 type words so there isn't the same need to group and isolate them 
 by prefix and/or context.


kind of disadvantage here to not refer by pointer. We are used to 
it, no?

 But is it *needed*? If you *must* work with multiple databases concurrently 
 and *cannot* have them attached, then SQLite is probably not the 
 right solution for you anyway ... it's an embedded C library with 
 limited concurrency and no user rights management after all. ;)
Ingo:
1-Mar-2006
And another question ... I have a table which conains string data 
...

sql {select * from person where firstname = "Ingo"}


does not find the row (tried with singel quotes, too). What am I 
doing wrong? It goes without saying, that the data is actually there, 
and I can find it using the following SQL

sql {select * from person where firstname like "%ingo%"}
Ashley:
1-Mar-2006
REBOL supports a maximum of 16 callbacks; so to avoid this error 
don't do %sqlite.r more than once within a script (and there is no 
sensible reason to do so anyway).


As for strings, remember that the driver mold's them; so they are 
actually stored as "string" (inclusive of quotes). You can reference 
them in one of two ways:

	sql {select * from table where col = '"string"'}

or

	sql ["select * from table where col = ?" "string"]


The second form is preferred as the binding is handled for you by 
the driver. I'm in the process of writing a SQLite Driver Guide (that 
covers this and other tricks) but it's a week or two away at the 
moment.
Ingo:
2-Mar-2006
Thanks Ashley,

I found out the first point by myself, and just added a check whether 
'sql has already been set before doing sqlite.r.

But so far I had no idea about the molding of strings, I could have 
tried for months, I guess ;-)
Ingo:
4-Mar-2006
Hi Ashlsy, I found a bug in sqlite.r. 'sql reuses its own return 
value on subsequent calls. so ...

>> all: sql "select * from persons"
== [["Ivo" "Hohmann" ...] ....]
>> me: sql {select * from persons where firstname = '"ingo"'}
== [["Ingo" "Hohmann" ...] ...]
>> all =? me
== true
Ashley:
4-Mar-2006
Deliberate design that. The last line of 'sql is simply:

	buffer

not:

	copy/deep buffer


This is important when dealing with a large number of values as you 
want to pass a reference not double the amount of memory used with 
a redundant copy/deep! I'll add this "gotcha" to the documentation 
I'm writing.
Ashley:
5-Mar-2006
clear buffer

 is also an optimization as it defaults to 32K values (make block! 
 1032 * 32) and I don't won't to reallocate it each SQL call. The 
 following benchmarks (Transactions Per Second) give some backround 
 to the design decisions I made:

	buffer				1744718
	copy buffer			282
	copy/deep buffer		76

	clear buffer			1144733
	buffer: copy []			824352
	buffer: make block! 32768	387


So the approach I took optimizes for large result sets by allocating 
a large buffer once up-front and then just referencing it thereafter.
Pekr:
9-Mar-2006
ah, I am dumb ... that is distribution of funcionality between sql 
and connect which confused me ...
Pekr:
9-Mar-2006
imo that should be somehow consolidated - why connect uses /flat 
to not blockify, and /direct to not mold/all, but sql function uses 
/raw for both of functionalities?
Pekr:
9-Mar-2006
I like those features being separated as in connect, du not understand 
why 'sql has /direct for not molding, and /raw combining /direct 
and /flat ... but it does lack /flat itself :-)
Ashley:
9-Mar-2006
/no-copy is a reasonable compromise, and fits with the /flat refinement 
in that the driver defaults to the expected "safe" behaviour. I'll 
add that to the next build.


XML output: I'm adding HTML output to the next build; is XML needed 
in addition to that? And if so, what does a "standard" table definition 
look like under XML (please provide a short example).


SQL refinements: the idea is that in most cases you specify all the 
refinements you need with CONNECT and just use SQL without any; except 
in the following two special cases:


1. SQL/direct: where you used CONNECT (without the /direct refinement), 
but need to access a *specific* table that does not need its TEXT 
column values MOLDed (e.g. sqlite_master)


2. SQL/raw: as above but flattens data. Used primary to access system 
tables / data, this ensures that values are always returned in a 
consistent format; lets you write code like:

	to file! third DATABASE


without having to worry about the format of the returned block(s).


Grammatical question. Do folks prefer I use the word INDEXES or INDICES 
to refer to more than one INDEX?
Ashley:
9-Mar-2006
SQL/raw: For the sake of clarity, I've renamed this /flat and changed 
all "SQL/raw" calls to "SQL/flat/direct".
Ashley:
11-Mar-2006
0.1.6 available at: http://www.dobeash.com/SQLite/sqlite.r


Now that the driver functionality has stabilized, this build focuses 
on delivering optimal performance. Changes of note include:

	- no-copy directive added

 - Added a new /info refinement to control when column names and widths 
 are obtained
	- main SQL loop rewritten to be approx twice as fast as 0.1.5
	- format / pad optimised (also about twice as fast as well)

 - IMPORT removed (better to use sqlite admin tool for large externel 
 loads / unloads)
	- Example code removed to http://www.dobeash.com/SQLite/demo.r

 - Code reordered and tidied up (directives appear at beggining of 
 context and routines defined on a single line each)

Enjoy!
Gabriele:
11-Mar-2006
btw, do you know if it's possible to separate sqlite's engine from 
the rest of the code? (sql, etc) we'd need only the low level stuff, 
file format, indexind etc.
Ashley:
14-Mar-2006
If someone has an SDK licence could they confirm this strange behaviour 
by replacing the last line of %sqlite.r with:

attempt [delete %test.db]
connect/create %test.db
sql "create table t (c)"
sql "insert into t values (1)"
print mold SQL ["select * from t where c = ?" 1]
wait 2


and encapping it with either enpro or enface. Run both the script 
and the encapped version and compare the output ... I get an empty 
block returned by any statement that makes use of bind variables 
and is encapped. DOing %sqlite.r from an encapped script works fine, 
as does something like:

	do uncompress #{789C...

so my only guess is it's a binding issue of some sort.
Ashley:
15-Mar-2006
One strange bug remains. Occasionally %demo.r will fail (typically 
selecting rows from Items) due to garbage characters that somehow 
get inserted. I have reduced the problem down to this script:

REBOL []

unless value? 'SQLite [do %sqlite.r]

repeat cnt 10 [
	prin ["^/Run" cnt "..."]
	;	Clean up from previous runs
	error? try [delete %test.db]
	error? try [delete %test.db-journal]
	;	Create Items (1000 rows) records
	prin " create ..."
	CONNECT/flat/create %test.db
	SQL "create table t (c1,c2,c3,c4,c5)"
	prin " insert ..."
	SQL "begin"
;	loop 1000 [
	repeat z 10000 [

;		SQL reduce ["insert into t values (?,?,?,?,?)" 1 "A 1" $1 1 $1 
* 1]

  SQL reduce ["insert into t values (?,?,?,?,?)" 1 reform ["A" 1] $1 
  1 $1 * 1]
	]
	SQL "commit"
	prin " select ..."
	SQL "select * from t"
	DISCONNECT
]

quit


Running the script should cause a failure like the following within 
the first couple of runs:


Run 1 ... create ... insert ... select ...** Syntax Error: Invalid 
tag -- <C
** Near: (line 1) À<C"
>> sqlite/direct?: true
== true
>> sql "select * from t where c2 like '%<%'"
== [1 {À<C^B"} "$1.00" 1 "$1.00"]


Changing the repeat to a loop seems to shift the error, often (but 
not always) making it take more runs to materialize. Replacing the 
reform with a string will often (but not always) allow all runs to 
complete successfully. Changing the number or order of INSERTed values 
also seems to shift the error. I'm not sure whether this is a REBOL 
or SQLite library error, but any help in tracking it down would be 
greatly appreciated.
sqlab:
16-Mar-2006
The high memory consumption and crashing of an process or should 
I say silently vanishing, that I observed with this routine after 
two consecutive runnings, I saw already  sporadic with the former 
releases after some sql errors and trying to resolve a busy lock 
on the db with some tricks, for example repeating a step.
Pekr:
16-Mar-2006
connect/create %test.db
sql "create table test (id, name, last_name)"
sql {insert into test values (1, "Petr", "Krenzelok")}
sql {select * from test}

; returns [[1 Petr Krenzelok]]   ... sqlite3 does not do that according 
to Bobik's info ... I am not sure I like it - it convert apparent 
string to word, I don't want that and I am not sure I want to use 
/direct for that, that seem like a reverse logic to me ...
Pekr:
16-Mar-2006
ah, now I see ... and I have questions .... Ashley, when the sql 
query is not block, but a string - you send the query as-is? Why 
the difference? with ' it works, with " it does not ... can the functionality 
be made just the same? I think most ppl are used to "quote" string, 
not to 'quote it like that' .... I would prefer driver to return 
an error for quotes, if they can't be used, instead of returning 
string as a word :-)
Pekr:
16-Mar-2006
it is inconsistent with:


sql ["insert into test values (1, ?, ?)" "Petr" "Krenzelok"] ; in 
this case it returns strings, not words ... imo string and block 
sql queries should be compatible
Graham:
16-Mar-2006
I'm not following this , but in sql ' is used as the quote character 
for literal strings, not "
Ashley:
16-Mar-2006
Hmm, adding /direct to the example posted previously and changing 
the last part of the INSERT to "... form $1 1 form $1 * 1" seems 
to work properly (100 error-free runs so far). The *only* difference 
then is in this line of the value binding logic:

	unless direct [val: mold/all val]

which if you change it to something like:

	unless direct [p: mold/all val]
	*bind-text sid i p length? p 0


seems to handle more runs before a failure. Thinking that mold/all 
might be the problem I then reran my /direct test with the following 
SQL statement:


 SQL reduce ["insert into t values (?,?,?,?,?)" 1 mold/all reform 
 ["A" 1] mold/all $1 1 mold/all $1 * 1]


which is functionally equivalent to the failing statement ... but 
no failures (after 100 runs). So, the conditions needed to reproduce 
this error [so far] are:

	SQLite library
	INSERT statement using a particular sequence of bind variables
	MOLD/ALL coded / used in a particular manner
	High volume of INSERTs

Now is that an obscure error or what? ;)
Ashley:
17-Mar-2006
But they are not the same way ...

	SQL "insert into t values ('text')
	SQL {insert into t values ('"text"')}

map to:


 SQL ["insert into t values (?)" "text"]	; with /direct refinement

 SQL ["insert into t values (?)" "text"]	; without /direct refinement


The first approach in each case is saying, "I want this value to 
be stored as a SQLite TEXT value which will not be LOADed upon retrieval"; 
while the second is saying, "I want this value to be stored as a 
MOLDed SQLite TEXT value which will be LOADed upon retrieval back 
into a REBOL string value (as opposed to the word 'text)".


A string! statement is strictly literal, it is passed onto SQLite 
with no parsing or conversion. If you want to bind values, use the 
block form ... that's what it's there for!
Graham:
20-Mar-2006
Does sqlite support timestamp/date fields ?  Is there a way to set 
a default value for a field ( so that on a sql insert, you don't 
have to explicitly mention that column  ) ?
Ashley:
20-Mar-2006
Graham, yes to all the above except timestamp/date fields. SQLite 
only supports 5 datatypes: Integer, Decimal, Binary, Null and Text. 
The driver (unless using the /direct refinement to connect) MOLDs 
and LOADs other REBOL types such as date!, pair!, etc into SQLite 
TEXT fields so date is certainly supported at the REBOL level (although 
an "order by date" clause will not give the expected results ... 
I tend to use 'sort/skip SQL "select id,date from t" 2' type constructs 
to achieve the desired result).


Given how common this later operation is (order by date) I'm looking 
at changing the way date is bound. Instead of just MOLDing it, if 
it is transformed to YYYY-MM-DD format then not only can LOAD recognize 
it but it can be sorted (as TEXT) directly by SQLite.
Ashley:
22-Mar-2006
Agreed. It's just that almost every datatype apart from date (pair! 
is also problematic) happens to sort correctly under SQLite as is; 
and changing date's TEXT representation so that it sorts correctly 
within SQLite is fairly easy. I'd rather write:

	result: SQL "select id,date from t order by date"


than:

	result: sort/skip SQL "select id,date from t"  2

as it's both easier to maintain and more efficient.
Ashley:
25-Mar-2006
Replace the column-text block in the SQL function with:

	[(
		either direct [
			[*column-text (sid) idx]
		][
			[
				s: v: *column-text (sid) idx
				while [s: find s {""}] [change/part s "" 2]
				load v
			]
		]
	)]

I've added this to the next build.
Ashley:
25-Mar-2006
0.1.9 posted with improved concatenation handling logic. In addition 
to handling strings you can now also do:

	SQL "select name||100 from customers"

and

	SQL {select id||'"-'"||name from customers}


Most REBOL types are supported (in concatenation type operations) 
although blocks may cause problems.
Robert:
3-Apr-2006
Value Binding: Is something like this possible as well?

	SQL ["select * from ? where col_1 = ?" mytable 1]
Robert:
3-Apr-2006
IMO it would be very handy, because those statements can be prepared 
and assigned to rebol words, for simple access in an application. 
It the SQL statement changes, I only have to do it at one place.
Ingo:
5-Apr-2006
I got an error in the 'sql func ...


** Script Error: length? expected series argument of type: series 
port tuple bitset struct
** Where: switch
** Near: *bind-text sid i val length?

the database is opened with /direct refinement.

The call is:
	sql ["select * from person where guid = ?" guid1]


Where I know, that the dataset with this guid exists, because I have 
just got it from another selsct.
The dataset contains only strings, some of them empty.


Well, this is it: ["h-o-h.org_20060326_182311691_1224" "Urte" "Hermann" 
"Urmeli" "" "" "" "" "" "" "" "" "" "" "Opera ID: 359" "" "" ""]

And I am using the right guid.

Any ideas?
Ingo:
5-Apr-2006
So, the error in one small message: 

>> sql ["select * from person where guid = ?" #"a"]

** Script Error: length? expected series argument of type: series 
port tuple bitset struct
** Where: switch
** Near: *bind-text sid i val length?
Ashley:
7-Apr-2006
You could always encrypt selective columns client-side (e.g. sql 
reduce ["insert into t values (?,?)" key encrypt string])
Ashley:
23-Apr-2006
anybody tested to open sqlite.r generated databases with a database 
manger?
 Not sure what you mean here. The following works fine for me:

	c:\> sqlite3.exe my-db.db

docs state that I get back the number of columns and rows
 ... no longer the case (docs need to be updated)


Most efficient way to get number of rows is sql "select count(*) 
from my-table"


Number of columns can be found by: (length? describe "my-table") 
/ 6

I can't get back the columns name

 ... use the DESCRIBE command, or CONNECT/info (which then populates 
 sqlite/columns and sqlite/widths for every query; or alternatly, 
 set sqlite/col-info? true / false for a particular query).
Ashley:
23-Apr-2006
A simple rows function:

	set 'rows make function! [
		"Return row count."
		table [string!]
	][
		first sql/flat/direct reform ["select count(*) from" table]
	]

just add it to the body of the sqlite context.
BrianH:
1-May-2006
No, not C pragma, a set of PRAGMA statements that SQLite extensions 
to SQL, for settings and diagnostics.
Terry:
4-May-2006
 wtcSQLite allows you to add/edit/delete indexes, fields, tables, 
 triggers, views, data, and manage multiple database aliases without 
 knowing any SQL at all. 
http://www.zend.com/php5/contest/contest.php?id=74&single=1

(it's phpmyadmin for sqlite)
Pekr:
22-May-2006
Ashley - Bobik is getting following error (not so with original sqlite3 
protocol):

>> sql "select * from kategorie"

== [[1 30 34 M30] [2 35 39 M35] [3 40 44 M40] [4 45 49 M45] [5 50 
54 M50] [6 55 59 M55] [7 60
 64 M60] [8 65 69 M65] [9 70 74 M70] [...
>> sql "select * from kartoteka"
** Script Error: Out of range or past end
** Where: sql
** Near: either all [block? v #"[" <> first s] [rejoin v] [v]
>>
Ingo:
24-Jun-2006
Does anyone understand this error?

>> sql "select * from comm"
** Script Error: Out of range or past end
** Where: sql
** Near: either all [block? v #"[" <> first s] [rejoin v] [v]
>>
>> sql "select guid from comm"

== [[h-o-h.org_20060326_182311681_3176] [h-o-h.org_20060326_182311681_7315] 
[h-o-h.org_20060326_182311701_2470] [h-o-h.org_2006032
6...
>> length? sql "select guid from comm"
== 541
>> probe tables

["comm" {CREATE TABLE comm ( guid, type, value, note, flags, keywords, 
reference, created, updated, deleted )} ;...
Ingo:
24-Jun-2006
Furthermore, I sometimes have the problem, that errors in sql statements 
are not caught by try, if I call it from a view gui. 
Is this a known problem?
Ingo:
28-Jun-2006
Hi Ashley, while trying to find a minimal code example ... I found 
the error ... ;-) 

That's the error message ...
** User Error: SQLite SQL logic error or missing database
** Near: make error! reform ["SQLite" error]

And it was caused by:

      if string? face/user-data [
         if error? set/any 'err try [

            set pAddress-disp first rule compose [pAddress get guid = (face/user-data) 
            *]
	; rule creates an sql string and starts calls 'sql with it
	; yadda yadda yadda ...
         ]
      ][probe disarm err]

Do you find the error??? 

Somehow the [probe disarm err] block moved to the wrong if ... 


I don't know how this could trigger _this_ error, but after I moved 
the block the error has not occurred again.
Pekr:
1-Aug-2006
OK, maybe it is just me, but I can't get enough permission for my 
CGI, even if run in -cs mode, for sqlite.log to be written to (the 
script works in console though, but I am root there, so ...). Could 
the driver be updated to work with log?: false variable? I can see 
logging on four places, but only on one place (sql function) it ever 
checks the variable ....
Ashley:
2-Aug-2006
From the User Guide: "Every connect, disconnect, error and statement 
retry is logged to %sqlite.log. This refinement adds SQL statements 
as well. While this can be useful to monitor what SQL statements 
are being issued and what the volume and distribution is; be sure 
to monitor the size of this file in high transaction environments."


If you really don't want any log output then just direct it to /dev/null
Pekr:
2-Aug-2006
ah, so this variable applies only to disable/enable logging of sql 
statements, right?
Ashley:
2-Nov-2006
'time is set in 'sql and used by 'format
Ladislav:
3-Nov-2006
I know that 'time is set in SQL, but it isn't used by FORMAT AFAICT
BrianH:
6-Nov-2006
From his blogs it appears that Carl is just extracting SQLite's btree 
and indexing engine, but leaving out the SQL stuff that duplicates 
functionality already in REBOL (think blocks and series functions). 
You may be able to access the data (a little unlikely), but it won't 
be SQLite support.
Ashley:
8-Nov-2006
Depends on the number and size of records you wish to handle, whether 
ACID is important to you, and whether you need SQL access or not.
Ashley:
9-Nov-2006
A good entry point if you just want to grab the SQL syntax is: http://www.sqlite.org/lang.html
Louis:
16-Nov-2006
What am I doing wrong here:

rebol []
do %sqlite.r
do %rebgui.r

if not exists? %id.txt [write %id.txt 1]

db: %indodex.db
either not exists? db [
    CONNECT/create/flat/direct/format db

    SQL "create table base (id, Nama, Alamat, Telefon, Handfon, Fax, 
    Email, Tgl_Nikah, Nota)"

    SQL "create table birthdays (id, Nama, Jenis, Hubungan, Tgl_Lahir, 
    Agama, Nota)"
][
    CONNECT/flat/direct/format db
]
unless value? 'ctx-rebgui [
	either exists? %rebgui-ctx.r [do %rebgui-ctx.r] [do %rebgui.r]
]
set-colors
tab-size: 120x55
fonts: reduce [font-sans-serif font-fixed font-serif "verdana"]
do show-cc: make function! [] [
display "IndoDex Ver. 1.0.1" [
    tab-panel #HW data [
        "Add" [

            label "Title:" priority: drop-list 30 #W "Pak" data ["Pak" "Ibu" 
            "Sdr." "Sdri." "Drs." "Dr." "Tuan" "Nyonya"] 20x5
            return
            label "Nama:" nama: field 
            return
            label "Alamat:" alamat: area 50x30
            return
            label "Telefon" telefon: field
            return
            label "Handfon" handfon: field
            return
            label "Fax:" fax: field
            return
            label "E-Mail:" email: field
            return
            label "Nota:" nota: area 50x30
            return
            button "Save" [
                (id: to-integer read %id.txt)

                SQL/flat/direct {insert into base values (id, Nama, Alamat, Telefon, 
                Handfon, Fax, Email, Tgl_Nikah, Nota)}
                (write %id.txt id)
                show-text ex-status "Saved"]
        ]
        "Edit" [
            
	]
	"Search" [
	]
    ]
]
]
do-events
Louis:
16-Nov-2006
This doesn't work either:


 SQL ["insert into base values (?, ?, ?, ?, ?, ?, ?, ?, ?)" ID, Nama, 
 Alamat, Telefon, Handfon, Fax, Email, Tgl_Nikah, Nota]
Ashley:
16-Nov-2006
Try reducing the block, as in:


 SQL reduce ["insert into base values (?, ?, ?, ?, ?, ?, ?, ?, ?)" 
 ID, Nama, Alamat, Telefon, Handfon, Fax, Email, Tgl_Nikah, Nota]
Louis:
16-Nov-2006
Here's the latest version:

rebol []
do %sqlite.r
do %rebgui.r
unless value? 'ctx-rebgui [
	either exists? %rebgui-ctx.r [do %rebgui-ctx.r] [do %rebgui.r]
]
set-colors
tab-size: 120x55
fonts: reduce [font-sans-serif font-fixed font-serif "verdana"]

if not exists? %id.txt [write %id.txt 1]
i: to-integer read %id.txt
i: i - 1
either not exists? %indodex.db [
    CONNECT/create %indodex.db

    SQL "create table base (ID, Title, Nama, Alamat, Telefon, Handfon, 
    Fax, Email, Tgl_Nikah, Nota)"

    SQL "create table birthdays (ID, Nama, Jenis, Hubungan, Tgl_Lahir, 
    Agama, Nota)"
][
    CONNECT %indodex.db
]
do show-cc: make function! [] [
set-colors
display "IndoDex Ver. 1.0.1" [
            label 16 "ID:" id: text (to-string i)
            return

            label 16 "Title:" title: drop-list 30 #W "Pak" data ["Pak" "Ibu" 
            "Sdr." "Sdri." "Drs." "Dr." "Tuan" "Nyonya"] 20x5
            return
            label 16 "Nama:" nama: field 
            return
            label 16 "Alamat:" alamat: area 50x30
            return
            label 16 "Telefon:" telefon: field
            return
            label 16 "Handfon:" handfon: field
            return
            label 16 "Fax:" fax: fax: field
            return
            label 16 "E-Mail:" email: field
            return
            label 16 "Nota:" nota: area 50x30
            return
            button "Save" [

                ;UNCOMMENT THE FOLLOWING LINES AND YOU WILL SEE THEY DON'T WORK. 
                ANYBODY KNOW WHAT IS WRONG?

                ;SQL reduce ["insert into base values (?, ?, ?, ?, ?, ?, ?, ?, ?, 
                ?)" id/text, title/text, nama/text, alamat/text, telefon/text, handfon/text, 
                fax/text, email/text, tgl_nikah/text, nota/text]

                ;SQL {insert into base values ('Pak' 'Ibu' 'Sdr.' 'Sdri.' 'Drs.' 
                'Dr.' 'Tuan' 'Nyonya' 'Jonew')}
                (i: to-integer i)
                (i: i + 1)
                (write %id.txt i)
                (i: to-string i)
            ]
            button "GUI Info [

                print [id/text " " title/text " " nama/text " " alamat/text newline]
            ]
            button "DB Info" [
                print TABLES
                SQLite/col-info?: true
                print SQL "select * from base"
                print SQLite/columns
            ]
            button "Halt" [
                halt
            ]
            button "Quit" [
                quit
            ]
]
]
do-events
Ashley:
16-Nov-2006
You have a few errors in there.


 - your values are comma seperated (e.g. use SQL reduce ["..." val1 
 val2 ...] instead

 - tgl_nikah/text appears in your INSERT but isn't present in your 
 display
	- your "DB Info" button can use ... print ROWS "base"
Louis:
1-Dec-2006
Ashley, I notice that sqlite.r value binding is missing some records 
when using LIKE.


>> sql ["select * from base where alamat like ?" "%Grand%"]   <<=====<<< 
This fails.
== "No rows selected."

>> sql ["select * from base where alamat like '%Grand%'"]      <<====<<< 
This finds a record.
Group: !CureCode ... web-based bugtracking tool [web-public]
Dockimbel:
18-Jun-2007
For an SQL expert, it shouldn't take more than one hour, I guess. 
Maybe even less, I didn't counted how much MySQL specific syntax 
or functions are used.
Dockimbel:
26-Aug-2008
Paul : if TRETBASE can support the same DB structure, support SQL 
JOINs (or similar feature), user and security management, not being 
more verbose than SQL, and being as fast as MySQL without using more 
memory, I'll drop MySQL at once and use TRETBASE as a backend in 
all my projects.
Dockimbel:
31-Aug-2008
I guess that it would also needs a few changes in the SQL requests 
also, MySQL specific features like LAST_INSERT_ID( ) need to be ported. 
Anyway, it shouldn't take more than a couple of hour to make it work 
with SQLite (once you have the right driver).
Oldes:
18-Nov-2008
Also I'm missing basic instalation notes...
1. to add into httpd.conf:
	webapp [
		virtual-root "/curecode"
		root-dir %www/curecode-r091/ ;or different dir
	]
2. To get a known admin password, change in private/build-db.sql:
EE10C315EBA2C75B403EA99136F5B48D 
to

21232F297A57A5A743894A0E4A801FC3  ;(enbase/base checksum/method "admin" 
'md5 16) = so the known password will be 'admin' for admin account

3. to run private/install.r script
Dockimbel:
18-Nov-2008
There's a bug in %index.rsp from a change I did last week in the 
statistics SQL code. Fixing...
Dockimbel:
24-May-2009
I could refresh the list below when you jump in Detail mode (and 
clear it when jumping in Search mode), but that means doing a quite 
big SQL query on all the tickets each time you switch from one mode 
to another...I tried to avoid that in exchange to a little less intuivite 
UI. Maybe there's some better solution.
101 / 6641[2] 34567