全部博文(1144)
分类: LINUX
2010-06-07 06:54:35
SQLite TutorialCopyright (c) 2004 by Mike Chirico mchirico@users.sourceforge.net This article explores the power and simplicity of sqlite3, starting with common commands and triggers. It then covers the attach statement with the union operation, introduced in a way that allows multiple tables, in separate databases, to be combined as one virtual table, without the overhead of copying or moving data. Next, I demonstrate the simple sign function and the amazingly powerful trick of using this function in SQL select statements to solve complex queries with a single pass through the data, after making a brief mathematical case for how the sign function defines the absolute value and IF conditions.
Although the sign function currently does not exist in , it is very easy to create in the "/src/func.c" file so that this function will be permanently available to all sqlite applications. Normally, user functions are created in C, Perl, or C++, which is also documented in this article. sqlite3 has the ability to store "blob", binary data. The sample program in the download, "eatblob.c", reads a binary file of any size into memory and stores the data in a user-specified field. All examples can be found in , and I encourage you to download these examples as you read this document. This tutorial was made with sqlite3 version 3.0.8. Getting StartedCommon CommandsTo create a database file, run the command "sqlite3", followed by the database name. For example, to create the database "test.db", run the sqlite3 command as follows: $ sqlite3 test.db SQLite version 3.0.8 Enter ".help" for instructions sqlite> .quit $ The database file test.db will be created, if it does not already exist. Running this command will leave you in the sqlite3 environment. There are three ways to safely exit this environment: .q, .quit, and .exit. You do not have to enter the sqlite3 interactive environment. Instead, you could perform all commands at the shell prompt, which is ideal when running bash scripts and commands in an ssh string. Here is an example of how you would create a simple table from the command prompt: $ sqlite3 test.db "create table t1 (t1key INTEGER PRIMARY KEY,data TEXT,num double,timeEnter DATE);" After table t1 has been created, data can be inserted as follows: $ sqlite3 test.db "insert into t1 (data,num) values ('This is sample data',3);" $ sqlite3 test.db "insert into t1 (data,num) values ('More sample data',6);" $ sqlite3 test.db "insert into t1 (data,num) values ('And a little more',9);" As expected, doing a $ sqlite3 test.db "select * from t1 limit 2"; 1|This is sample data|3| 2|More sample data|6| In the statement above, the limit clause is used, and only two rows are displayed. For a quick reference of SQL syntax statements available with SQLite, see . There is an offset option for the limit clause. For instance, the third row is equal to the following: "limit 1 offset 2". $ sqlite3 test.db "select * from t1 order by t1key limit 1 offset 2"; 3|And a little more|9| The ".table" command shows the table names. For a more comprehensive list of tables, triggers, and indexes created in the database, query the master table "sqlite_master", as shown below. $ sqlite3 test.db ".table" t1 $ sqlite3 test.db "select * from sqlite_master" table|t1|t1|2|CREATE TABLE t1 (t1key INTEGER PRIMARY KEY,data TEXT,num double,timeEnter DATE) All SQL information and data inserted into a database can be extracted with the ".dump" command. Also, you might want to look for the "~/.sqlite_history" file. $ sqlite3 test.db ".dump" BEGIN TRANSACTION; CREATE TABLE t1 (t1key INTEGER PRIMARY KEY,data TEXT,num double,timeEnter DATE); INSERT INTO "t1" VALUES(1, 'This is sample data', 3, NULL); INSERT INTO "t1" VALUES(2, 'More sample data', 6, NULL); INSERT INTO "t1" VALUES(3, 'And a little more', 9, NULL); COMMIT; The contents of the ".dump" can be filtered and piped to another database. Below, table t1 is changed to t2 with the sed command, and it is piped into the test2.db database. $ sqlite3 test.db ".dump"|sed -e s/t1/t2/|sqlite3 test2.db TriggersAn insert trigger is created below in the file "trigger1". The Coordinated Universal Time (UTC) will be entered into the field "timeEnter", and this trigger will fire after a row has been inserted into the table t1. -- ******************************************************************** -- Creating a trigger for timeEnter -- Run as follows: -- $ sqlite3 test.db < trigger1 -- ******************************************************************** CREATE TRIGGER insert_t1_timeEnter AFTER INSERT ON t1 BEGIN UPDATE t1 SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid; END; -- ******************************************************************** The AFTER specification in ..."insert_t1_timeEnter AFTER..." is necessary. Without the AFTER keyword, the rowid would not have been generated. This is a common source of errors with triggers, since AFTER is not the default, so it must be specified. If your trigger depends on newly-created data in any of the fields from the created row (which was the case in this example, since we need the rowid), the AFTER specification is needed. Otherwise, the trigger is a BEFORE trigger, and will fire before rowid or other pertinent data is entered into the field. Comments are preceded by "--". If this script were created in the file "trigger1", you could easily execute it as follows. $ sqlite3 test.db < trigger1 Now try entering a new record as before, and you should see the time in the field timeEnter. $ sqlite3 test.db "insert into t1 (data,num) values ('First entry with timeEnter',19);" $ sqlite3 test.db "select * from t1"; 1|This is sample data|3| 2|More sample data|6| 3|And a little more|9| 4|First entry with timeEnter|19|2004-10-02 15:12:19 The last value has timeEnter filled automatically with Coordinated Universal Time, or UTC. If you want localtime, use For the examples that follow, the table "exam" and the database "examScript" will be used. The table and trigger are defined below. Just like the trigger above, UTC time will be used. -- ******************************************************************* -- examScript: Script for creating exam table -- Usage: -- $ sqlite3 examdatabase < examScript -- -- Note: The trigger insert_exam_timeEnter -- updates timeEnter in exam -- ******************************************************************* -- ******************************************************************* CREATE TABLE exam (ekey INTEGER PRIMARY KEY, fn VARCHAR(15), ln VARCHAR(30), exam INTEGER, score DOUBLE, timeEnter DATE); CREATE TRIGGER insert_exam_timeEnter AFTER INSERT ON exam BEGIN UPDATE exam SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid; END; -- ******************************************************************* -- ******************************************************************* Here's an example usage: $ sqlite3 examdatabase < examScript $ sqlite3 examdatabase "insert into exam (ln,fn,exam,score) values ('Anderson','Bob',1,75)" $ sqlite3 examdatabase "select * from exam" 1|Bob|Anderson|1|75|2004-10-02 15:25:00 As you can see, the PRIMARY KEY and current UTC time have been updated correctly. Logging All Inserts, Updates, and DeletesThe script below creates the table examlog and three triggers (update_examlog, insert_examlog, and delete_examlog) to record updates, inserts, and deletes made to the exam table. In other words, whenever a change is made to the exam table, the changes will be recorded in the examlog table, including the old value and the new value. If you are familiar with MySQL, the functionality of this log table is similar to MySQL's binlog. See if you would like more information on MySQL's log file. -- ******************************************************************* -- examLog: Script for creating log table and related triggers -- Usage: -- $ sqlite3 examdatabase < examLOG -- -- -- ******************************************************************* -- ******************************************************************* CREATE TABLE examlog (lkey INTEGER PRIMARY KEY, ekey INTEGER, ekeyOLD INTEGER, fnNEW VARCHAR(15), fnOLD VARCHAR(15), lnNEW VARCHAR(30), lnOLD VARCHAR(30), examNEW INTEGER, examOLD INTEGER, scoreNEW DOUBLE, scoreOLD DOUBLE, sqlAction VARCHAR(15), examtimeEnter DATE, examtimeUpdate DATE, timeEnter DATE); -- Create an update trigger CREATE TRIGGER update_examlog AFTER UPDATE ON exam BEGIN INSERT INTO examlog (ekey,ekeyOLD,fnOLD,fnNEW,lnOLD, lnNEW,examOLD,examNEW,scoreOLD, scoreNEW,sqlAction,examtimeEnter, examtimeUpdate,timeEnter) values (new.ekey,old.ekey,old.fn,new.fn,old.ln, new.ln,old.exam, new.exam,old.score, new.score, 'UPDATE',old.timeEnter, DATETIME('NOW'),DATETIME('NOW') ); END; -- -- Also create an insert trigger -- NOTE AFTER keyword ------v CREATE TRIGGER insert_examlog AFTER INSERT ON exam BEGIN INSERT INTO examlog (ekey,fnNEW,lnNEW,examNEW,scoreNEW, sqlAction,examtimeEnter,timeEnter) values (new.ekey,new.fn,new.ln,new.exam,new.score, 'INSERT',new.timeEnter,DATETIME('NOW') ); END; -- Also create a DELETE trigger CREATE TRIGGER delete_examlog DELETE ON exam BEGIN INSERT INTO examlog (ekey,fnOLD,lnNEW,examOLD,scoreOLD, sqlAction,timeEnter) values (old.ekey,old.fn,old.ln,old.exam,old.score, 'DELETE',DATETIME('NOW') ); END; -- ******************************************************************* -- ******************************************************************* Since the script above has been created in the file examLOG, you can execute the commands in sqlite3 as shown below. Also shown below is a record insert, and an update to test these newly-created triggers. $ sqlite3 examdatabase < examLOG $ sqlite3 examdatabase "insert into exam (ln,fn,exam,score) values ('Anderson','Bob',2,80)" $ sqlite3 examdatabase "update exam set score=82 where ln='Anderson' and fn='Bob' and exam=2" Now, by doing the select statement below, you will see that examlog contains an entry for the insert statement, plus two updates. Although we only did one update on the commandline, the trigger "insert_exam_timeEnter" performed an update for the field timeEnter; this was the trigger defined in "examScript". In the second update, we can see that the score has been changed. The trigger is working. Any change made to the table, whether by user interaction or another trigger, is recorded in the examlog. $ sqlite3 examdatabase "select * from examlog" 1|2||Bob||Anderson||2||80||INSERT|||2004-10-02 15:33:16 2|2|2|Bob|Bob|Anderson|Anderson|2|2|80|80|UPDATE||2004-10-02 15:33:16|2004-10-02 15:33:16 3|2|2|Bob|Bob|Anderson|Anderson|2|2|82|80|UPDATE|2004-10-02 15:33:16|2004-10-02 15:33:26|2004-10-02 15:33:26 Again, pay particular attention to the AFTER keyword. Remember that by default, triggers are BEFORE, so you must specify AFTER to insure that all new values will be available if your trigger needs to work with any new values. UTC and LocaltimeNote that sqlite> select datetime('now'); 2004-10-18 23:32:34 sqlite> select datetime('now','localtime'); 2004-10-18 19:32:46 There is an advantage to inserting UTC time like we did with the triggers above, since UTC can easily be converted to localtime after UTC has been entered in the table. See the command below. By inserting UTC, you avoid problems when working with multiple databases that may not share the same timezone and/or dst settings. By starting with UTC, you can always obtain the localtime. (Reference: ) CONVERTING TO LOCALTIME: sqlite> select datetime(timeEnter,'localtime') from exam; Other Date and Time CommandsIf you look in the sqlite3 source file "./src/date.c", you will see that datetime takes other options. For example, to get the localtime, plus 3.5 seconds, plus 10 minutes, you would execute the following command: sqlite> select datetime('now','localtime','+3.5 seconds','+10 minutes'); 2004-11-07 15:42:26 It is also possible to get the weekday where 0 = Sunday, 1 = Monday, 2 = Tuesday ... 6 = Saturday. sqlite> select datetime('now','localtime','+3.5 seconds','weekday 2'); 2004-11-09 15:36:51 The complete list of options, or modifiers as they are called in this file, are as follows: NNN days NNN hours NNN minutes NNN.NNNN seconds NNN months NNN years start of month start of year start of week start of day weekday N unixepoch localtime utc In addition, there is the "strftime" function, which will take a timestring, and convert it to the specified format, with the modifications. Here is the format for this function: ** strftime( FORMAT, TIMESTRING, MOD, MOD, ...) ** ** Return a string described by FORMAT. Conversions as follows: ** ** %d day of month ** %f ** fractional seconds SS.SSS ** %H hour 00-24 ** %j day of year 000-366 ** %J ** Julian day number ** %m month 01-12 ** %M minute 00-59 ** %s seconds since 1970-01-01 ** %S seconds 00-59 ** %w day of week 0-6 sunday==0 ** %W week of year 00-53 ** %Y year 0000-9999 Below is an example. sqlite> select strftime("%m-%d-%Y %H:%M:%S %s %w %W",'now','localtime'); 11-07-2004 16:23:15 1099844595 0 44 The ATTACH Command: Build a Virtual Table that Spans Multiple Tables on Separate DatabasesThis is a very powerful concept. As you have seen, sqlite3 works with a local database file. Within this local database, multiple tables can be created. This section will examine a technique to combine multiple tables with the same field layout that exist in separate database files into a single virtual table. On this single virtual table, you will see how selects can be performed. There is no overhead in copying or moving data. No data gets copied or moved, period. This is the ideal situation when working with very large tables. Suppose the computers on your network record port scans from to a local sqlite3 file. Provided you have access to the individual database files, via NFS mount or samba mount, you could virtually combine the tables from all your computers into one virtual table to perform database queries in an effort to identify global patterns of attack against your network. This example will be done with the examdatabase, since we still have the scripts that were used for the exam table. We can easily create a new database "examdatabase2", along with a new exam table, by executing the following script from the bash shell: $ sqlite3 examdatabase2 < examScript $ sqlite3 examdatabase2 < examLOG $ sqlite3 examdatabase2 "insert into exam (ln,fn,exam,score) values ('Carter','Sue',1,89); insert into exam (ln,fn,exam,score) values ('Carter','Sue',2,100);" $ sqlite3 examdatabase2 "select * from exam" 1|Sue|Carter|1|89|2004-10-02 16:04:12 2|Sue|Carter|2|100|2004-10-02 16:04:12 To combine the two database files, use the After the "attach" database command is performed, the ".database" command can be used to show the location of the individual database files. The location follows the alias. See the example below. $ sqlite3 SQLite version 3.0.8 Enter ".help" for instructions sqlite> attach database 'examdatabase' as e1; sqlite> attach database 'examdatabase2' as e2; sqlite> .database seq name file --- --------------- ---------------------------------------------------------- 0 main 2 e1 /work/cpearls/src/posted_on_sf/sqlite_examples/sqlite_exam 3 e2 /work/cpearls/src/posted_on_sf/sqlite_examples/sqlite_exam sqlite> To select all data from both tables, perform the union of two select statements as demonstrated below. Note that by adding 'e1' and 'e2' to the respective selects, it is possible to identify which database the returned records are coming from. sqlite> select 'e1',* from e1.exam union select 'e2',* from e2.exam; e1|1|Bob|Anderson|1|75|2004-10-02 15:25:00 e1|2|Bob|Anderson|2|82|2004-10-02 15:33:16 e2|1|Sue|Carter|1|89|2004-10-02 16:04:12 e2|2|Sue|Carter|2|100|2004-10-02 16:04:12 To summarize: A query was performed on two tables that resided in separate databases. This union created the virtual table. The select syntax is as follows: Here is a query example performed on this virtual table. Suppose you wanted the maximum score by exam across databases. No problem. You got the maximum score for each exam, but who does it below to? Find the ln and fn, but be careful; if you add "ln" and "fn" to the first part of the select, you will get the wrong answer. "Anderson", "Bob" happens to be the name that dropped down in this select statement. It is not the correct answer. If, by chance, you got the correct answer by doing this query, it is because you entered the names in a different order. If that is the case, perform the query below, which takes the min(score) and gets an error on one of these examples.
Here, the min(score) is queried. By chance, because of the order in which data was entered into this table, the correct answer is displayed. Clearly, there needs to be a better way of finding out who got the maximum and minimum scores for each exam. Here is the correct SQL statement which will always give the correct answer: Or it can be done as two independent select statements as follows: What if you wanted a pivot table in which the scores are listed across the top as exam1,exam2,..examN for each person? For example: Also, is there a way to display the deltas between exams, to have a fifth column that would show 7 points (82-75) or the delta between exam1 and exam2 and similar data for Sue Carter?
Such power select statements can be done with the sign function. And unlike the case statement, the sign function can be placed in the GROUP BY and HAVING expressions of a SELECT statement. For example, taking a look at the general syntax of the SELECT statement, the sign function can be used anywhere you see an expression or expression-list. The sign function does not exist in sqlite, but that is not a problem, since we can easily create it.
As a side note, you may wonder why you should create the sign function. Instead, why not create an IF or IIF function? The main reason is that the IF statement is not standard on all databases, and, on some databases where it is standard (MySQL), it was created incorrectly. Yes, if you are a MySQL user, take a look at the following for an example of MySQL's incorrect IF statement and how the sign function solves this problem.
It may come as a shock, but the problems in the last section, and much more, can be solved using the sign function. This is just the simple function in which sign(-200)=-1,.. sign(-1)=-1, sign(0)=0, sign(1)=1,.. sign(300)=1. So if the number is > 0 a 1 is returned. Zero is the only number that returns zero. All negative numbers return -1. Again, this simple function does not exist in sqlite, but you can easily create it, permanently. The next section will focus on the creation of this function, but here, the mathematical properties are explained.
The sign function can define the absolute value function abs() as the value of a number times its sign, or sign(x)*(x), abbreviated sign(x)(x). Here is a more detailed look at this function: Comparisons can be made with the sign function between two variables x and y. For instance, if sign(x-y) is 1, then, x is greater than y. Now look closely at the three statements below. The sign function starts to resemble an IF statement; a 1 is returned if and only if x = y. Thoroughly understanding the statements below is important, as the rest of the discussion quickly builds from these examples. It is possible to return a 1 if and only if x < y, otherwise return a zero. The last example is known as the delta for x To summarize the following if statement, note the introduction of a third variable, z: The above expression, in Delta notation, is the following: Here is an interesting example: First, take the Cartesian product to show all possible combinations of x and y. After the sign function is created (which we will do in the next section), using the above table, we could examine Delta[x!=y] as follows; Note that every time x is not equal to y, abs(sign(x.value-y.value)) returns a 1. After the sign function is created, these example will run. This is extremely powerful. To show that we have created a condition statement without using the where or group by statements, consider the following example. z.value will only be displayed in the right hand column when x.value != y.value. Sqlite functions are defined in "./src/func.c". In this file, the name of this function will be "signFunc". The user will call this function in sqlite as sign(n). It will hold only a single variable.
It is helpful to model the sign function after the abs function "absFunc", since they are very similar. If fact, I would highly recommend looking at the abs function any time a new version of sqlite is released.
You will want to follow these steps: First, copy the abs function "absFunc" and make the following changes:
For a closer look, below is the section that changed. Look here for the complete file: . Now, back to the problem of creating a pivot table for displaying exam scores in a spreadsheet-like format. First, more data is is needed. By the way, if have not added any data, the following script, , will create the necessary tables and insert the data. Below is the select statement for generating a pivot table for four exams on the table exams. Below is the select statement, like the statement above. However, it works on the virtual table, or the combined exam tables from the databases examdatabase and examdatabase2. Taking a closer look at the results, it's very easy to see that Anderson, Bob got 75 on the first exam, 82 on the second, 92 on the third, and 95 on the forth. Likewise, Stoppard received 88, 90, 92, and 95, respectively. Now back to the question of finding the top scores for each exam in one select statement. That is, finding the top scores for the combined tables. First, a look at all the data: Below, continuing with the same attached setup, is an example of horizontal averages and horizontal maximum values. Try finding the deltas, or the differences between each exam score. For hints on this, see the end of in the LONGWINDED TIPS section.
Consider the reverse: Suppose you had a pivot table, or the data in a spreadsheet-like format, and you wanted a normalized table of exams. For this example, the table nonormal is needed. This table is defined and created as follows: The nonormal table was created in the examdatabase, since "e1." was given before the name. Again, the objective here is to go backwards and create a normalized table from the pivot table, a table that will list all exam scores in one field and all the exam numbers in another, without having a separate field for each exam. In addition, the goal is to do all this in one select statement without looping through the data. First, it is necessary to create a number table, "enum", and it must have the field "e" from 1..N where N is the number of exams (which is four in this case). The coalesce function is used in an interesting way for this example. For more examples, see .
Assume you have the following table of names, ages, and salaries. Find the age, name, and salary of the youngest person making the overall highest salary, or first find the highest salary, then, from this group, select the youngest person. Once you have the data entered, you will have the following; The following select will give you the youngest person making the top salary in the company: This is the correct answer. The highest salary is 94 for Bob and Tom. Tom is the youngest at 24.
Why the number 1000? Well, no one lives to be 1000, so we know that age will never be >= 1000. Therefore, max(salary*1000-age) will clearly choose the highest salary independent of age, as long as salary is >= 1. In cases of a tie in salary, the youngest person will subtract the least amount from the salary, so this value will return as the highest. It's easy to remove the salary part from this number. Since salary is multiplied by 1000, it will disappear with mod 1000, since it's a perfect factor of 1000.
To understand how this works, it is helpful to break the statement into separate, smaller parts, as follows: But what about the negative value for age? With the non-Knuth method of the mod function, "%", when x < 0, then x % y will return x, if abs(x) < abs(y).
x % y is defined as follows: and undefined for y == 0. C and Fortran use this method.
In contrast, the Knuth method, found in Python and accepted in mathematics, defines this function as follows: and equal to x if y == 0
The difference between the two shows up with negative values for x.
Or, put another way, as long as -x != y, then -x % y = -x. For example, assume x=4 and y=5, then -4 % 5 will return a -4. Here are a few other examples. Again this is not the Knuth method for the mod function. So what we are really doing is the following: The following is a simple C program, , which will open a database and execute a SQL string. The command to compile and run the program is shown below. Note the "-Wl,-R/usr/local/lib" options, which will be needed if you installed the sqlite3 source, since the path "/usr/local/lib" may not be listed in your "/etc/ld.so.conf" file. You either have to use the compile option above or add the directory where the sqlite3 library "libsqlite3.so" is installed to the file "/etc/ld.so.conf", then run After you have entered and compiled the program, it will run as follows: There are really only three important statements, It is possible to build a class, SQLITE3 (defined below), which reads the returned data into a vector. Note that instead of using the The complete program can be found in or viewed here: .
With the class defined above, it can be used in The following, still assuming this code will be entered in main or a function, is an example of printing the data from a select. Note the headings section and the data sections. There are two types of functions, aggregate functions and simple functions. Simple functions like sign(), which was created above, can be used in any expression. Aggregate functions like "avg()" can only be used in the select statement. Some functions like "min" and "max" can be defined as both. min() with 1 argument is an aggregate function, whereas min() with an unlimited number of arguments is a simple function.
Here is an example which illustrates the difference: Note above that the min() function, with only one variable, is an aggregate function. Since it is only an aggregate function, it cannot be used after the If you add a second argument, you're calling the simple function. Note below that each row is compared to 2.3. Look closely; there is a subtle but important difference here. Below is an example of the sign function. It is called msignFunc so as not to interfere with the permanent sign function that was created earlier. This function is initiated as follows: Note that "msign" is the name of the function in sqlite3. It is the name you would use in a select statement: "select msign(3);". The 1 is the number of arguments. The msign function here only takes one argument. SQLITE_UTF8 is for the text representation. Then, skipping over NULL, &msignFunc is the name of the C function. The last two values must be NULL for a simple function; again, a simple function can be used in any part of the select A good place to look for ideas on creating functions is the ./src/func.c file in the sqlite3 source. Suppose you would like to create a new sum function call S. It will create the aggregate sum of the rows.
The following data is used to explain this function. Now for how the function S will create a list of the sums. Unlike the standard aggregate sum() function, a list is returned. Note that a column which contains the values in the table (1,2,3,4,5) shows the cumulative sum (1,1+2=3,1+2+3=6,1+..) in a list. This is different from any function defined in ./src/func.c, since the data must be in a string.
To view this example and all other examples, see the . Since a list is returned, this example will use the C++ std::stringstream, since this is fast and well suited for all types of data, integer, double, and text.
Since S is an aggregate function, there are two functions, "SStep" and "SFinalize". Aggregate functions always have a "Step" and a "Finalize". "Step" is called for each row, and after the last row, the "Finalize" function is called.
Both the Step and the Finalize can make use of a structure for holding the cumulated data collected from each row. For this function, the structure SCtx is defined below. std::stringstream is global. I would not advise putting an additional variable in SCtx, "char *ss". You may think that this could be dynamically increased with realloc, which will work. However, the problem is freeing the memory hanging off the structure. There's a bit of confusion here. As the sqlite documentation correctly points out, the structure SCtx will be freed; but again, in my testing, any additional memory allocated off members in the structure will not. On the other hand, an array of std:stringstrings "BS" will have to be kept for when this function is called more than once in the same select "select S(a),S(b),...S(100th)" The overhead appears minimal. Below is the step function. p gets initialized the first time through SStep. On the first pass, all the values in the SCtx structure will be zeroed. This is a feature of "sqlite3_aggregate_context". Since std::stringstream s0 is defined as a global variable, care will have to be taken to ensure that when S is called in the same select " The line: will initialize p->sum, p->cnt, and p->sscnt to zero on the first entry into this function. On each successive entry, the old values be passed back. Although the std:stringstream ss variable is global, S(a) called in the select uses ss[0], S(b) will use ss[1], etc.
Also note the comment "If the simple function is not used, this comes into play". Below that statement, i walks through the argument count. It is possible to have a function name "S", in this case defined as both an aggregate function and a simple function. The distinction is made with the number of arguments in the calling function. This is set in sqlite3_create_function. For example, a name could be assigned to a simple function and an aggregate function. Normally, this is set up so that the simple function takes two or more arguments max(1,2,3,4,5) and the aggregate function just takes one argument max(a). Take a look at Here is the Finalize function: After all the rows in The user functions "SStep" and "SFinalize" need to be added to the SQL language interpreter. This is done with the "sqlite3_create_function": Note the 1 for the third argument. This aggregate function is used when one argument is passed. To have it both ways, to have "S" defined as both an aggregate and a simple function, an SFunc would have to be created. That could handle 2 to N variables. Once this function is created, the additional "sqlite3_create_function" would be defined in Here is an example SFunc function: Now, S works as both a simple function and an aggregate function. The simple function can go in any expression, but the aggregate only works after the select. Hence, this goes back to the power of the sign function, which is a simple function. For a few more examples, take a look at in the . There are some interesting functions there. For instance, there is an I or index function that works as follows: , which takes the index in the list. The first index starts at zero.
First, a demonstration of how the program works. This program is a C API which inserts binary (blob) data into a table.
The program can be run in two ways. First, script commands can be redirected into it. For example, you can create the following script file "sqlcommands": Note the "?" on the line " The image file "test.png" will be read into the program and inserted into the field b, since this is where the question mark is placed.
The program also works interactively, as follows: The blob data is not shown. Instead, it is written to the file outdata.n.png, where n is the record number.
The program works by reading all of the binary data from the filename given as the third argument to the command. The complete file is read into memory. One way to do this is to get the total file size first, then allocate that amount of memory with malloc. That approach is not taken here. Instead, a more general approach is used. For instance, if you were to read data from a socket, you may not know beforehand how big the file will be. This general approach will take advantage of the One line 3, the first time this function is called, the variable size is the current number of bytes allocated. If no memory has been allocated (size is 0), the new size will be INIT_SIZE. For this program, INIT_SIZE is set to 1024 in the define statement. However, if size is greater than zero, the new size will be the initial size plus memindx, which starts at 1024. As you can see, the number returned increases exponentially. "memindx" is doubled each time this function is called. This doubled value is added to the size. So, the function gives us a number that we can pass to realloc.
realloc works as follows: If realloc is successful, it will copy the contents pointed to by buf to a location of memory with the larger size memnext, then free the old region of memory. This new region of memory will be assigned to tbuf. Since the old location (the location pointed to by *buf) has been released, we need to assign the new value to *buf ( *buf = tbuf).
If realloc cannot get the new size memnext, *buf is left untouched and tbuf will be null.
Note that in the above program, buf is a pointer to a pointer, *buf is a pointer, and **buf is the first byte of data.
To use Perl with sqlite3, DBI and DBD::SQLite must be installed. To install the packages from CPAN, use the following commands. The following program will create a database and enter records: For a more elaborate Perl example that defines functions, see in the .
Also, consider using the Perl Debugger, for stepping through complex Perl sqlite programs where you are not sure of what is returned. To get into the Perl debugger, execute the following command, and to get out of the Perl Debugger type "q".
This simple bash allows you to take notes. The notes consist of a line of text followed by an optional category. It doesn't require you to type This enters the text into a notes table under the category "sqlite3". Whenever a second field appears, it is considered the category. To extract records for the day, enter "n -l" (which is similar to "l -l") to "note list".
With just "n", help is listed for all the commands.
This trick works on sqlite version 3.2.7 and all historical versions. However, it is not guaranteed to work on all future versions. Still, this is an interesting trick.
Suppose you have two similar table structures and you want to update missing rows. This is easier to show with an example.
Above when table t0 is compared to t1 values 1 and 3 are missing. It is possible to update these these rows as follows:
Note above the plus sign in "+t0.rowid" so that you do not get row locking errors.
: There are over 200 Linux tips and tricks in this article. That is over 150 pages covering topics from setting and keeping the correct time on your computer, permanently deleting documents with shred, making files "immutable" so that root cannot change or delete, setting up more than one IP address on a single NIC, monitering users and processes, setting log rotate to monthly with 12 months of backups in compressed format, creating passwords for Apache using the htpasswd command, common Perl commands, using cfengine, adding users to groups, finding out which commands are aliased, query program text segment size and data segment size, trusted X11 forwarding, getting information on the hard drive including the current temperature, using Gnuplot, POVRAY and making animated GIFs, monitoring selective traffic with tcpdump and netstat, multiple examples using the find command, getting the most from Bash, plus a lot more. You can also down this article as a text document for easy grepping.
: This tutorial walks you through implementing disk quotas for both users and groups on Linux, using a virtual filesystem, which is a filesystem created from a disk file. Since quotas work on a per-filesystem basis, this is a way to implement quotas on a sub-section, or even multiple subsections of your drive, without reformatting. This tutorial also covers quotactl, or quota's C interface, by way of an example program that can store disk usage in a SQLite database for monitoring data usage over time.
: If the system administrator deliberately filters out all traffic except port 22 (ssh), to a single server, it is very likely that you can still gain access other computers behind the firewall. This article shows how remote Linux and Windows users can gain access to firewalled samba, mail, and http servers. In essence, it shows how openSSH and Putty can be used as a VPN solution for your home or workplace.
: These steps will show you how to create a functioning Linux system, with the latest 2.6 kernel compiled from source, and how to integrate the BusyBox utilities including the installation of DHCP. Plus, how to compile in the OpenSSH package on this CD based system. On system boot-up a filesystem will be created and the contents from the CD will be uncompressed and completely loaded into RAM -- the CD could be removed at this point for boot-up on a second computer. The remaining functioning system will have full ssh capabilities. You can take over any PC assuming, of course, you have configured the kernel with the appropriate drivers and the PC can boot from a CD. This tutorial steps you through the whole processes.
: This article explains how to build grammars and programs using the lemon parser, which is faster than yacc. And, unlike yacc, it is thread safe. : This is a step by step tutorial on how to compile the 2.6 kernel from source. You can take a disk file, format it as ext2, ext3, or reiser filesystem and then mount it, just like a physical drive. Yes, it then possible to read and write files to this newly mounted device. You can also copy the complete filesystem, sinc\ e it is just a file, to another computer. If security is an issue, read on. This article will show you how to encrypt the filesystem, and mount it with ACL (Access Control Lists), which give you rights beyond the traditional read (r) write (w) and execute (x) for the 3 user groups file, owner and other. : What? There are 61 seconds in a minute? We can go back in time? We still tell time by the sun? Mike Chirico, a father of triplets (all girls) lives outside of Philadelphia, PA, USA. He has worked with Linux since 1996, has a Masters in Computer Science and Mathematics from Villanova University, and has worked in computer-related jobs from Wall Street to the University of Pennsylvania. His hero is Paul Erdos, a brilliant number theorist who was known for his open collaboration with others.
|