-
Notifications
You must be signed in to change notification settings - Fork 0
/
README.sqlapi
274 lines (224 loc) · 12.4 KB
/
README.sqlapi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
README.sqlapi - Database abstraction class for MRBS
-----------------------------------------------------------------------------
MRBS utilises a database abstraction class, currently implemented for
MySQL (>= 5.1) and PostgreSQL (>= 8.2). It was written for MRBS but may
be useful in other applications.
The class supports multiple connections to arbitrary databases,
but there is also a simple wrapper function to allow use of the default
MRBS database without the user always passing a database object
around. This is the function "db()" defined in dbsys.inc.
The class supports multiple pending results for each connection. It
can be configured to use PHP persistent (pooled) database connections,
or normal (single use) connections.
CAUTION: Before using PHP persistent database connections with PostgreSQL,
be sure your PostgreSQL postmaster can support enough backends. In theory,
and to be completely safe, it needs to be able to support at least as many
concurrent connections as your Apache "MaxClients" setting times the number
of unique persistent connection strings (PostgreSQL conninfo's, unique
combinations of user/password/database) implemented on your site. Note that
the default for PostgreSQL is a maximum of 32 connections, and the default
for Apache MaxClients is 150. If you want to use persistent connections,
see the $persist parameter to DBFactory::create() below.
-----------------------------------------------------------------------------
To use this package, include "dbsys.inc" after defining the following
variables:
$dbsys = The database abstraction to use, 'mysql' or 'pgsql'
$db_host = The hostname of the database server, or "localhost"
$db_login = The username to use when connecting to the database
$db_password = The database account password
$db_database = The database name
Optionally, you can define:
$db_persist = true;
if you want to use persistent connections.
If using PostgreSQL, and the database server is on the same host as the web
server, you can specify $db_host="localhost" to use TCP, or $db_host="" to
use Unix Domain Sockets. Generally this won't make much difference, but if
your server runs without the -i option, it will only accept Unix Domain
Socket connections, so you must use $db_host="".
After your script includes the file, you can get the default database
connection object by calling db().
If an error occurs while trying to connect, a message will be output
followed by a PHP exit.
The way MRBS uses this is to define a configuration file config.inc.php with
the above variables plus:
$dbsys = "pgsql"; // or: $dbsys = "mysql";
Then, each PHP script which wants to connect to the database starts with:
include "config.inc.php";
include "dbsys.inc";
If you do this, be sure the web server will not serve config.inc.php to
clients, for security reasons.
-----------------------------------------------------------------------------
Notes on improving SQL portability:
+ Use standard SQL-92 as much as possible.
+ Where it is not possible to use SQL-92, use or implement an sql_syntax_*
function which hides the database differences (see below).
+ Don't use SQL-92 reserved words as column or table names.
+ Use PHP functions rather than database functions where practical.
+ Don't reply on specific formats for output of DATETIME types.
+ Don't quote numeric type values in SQL statements.
SQL-92 standard things to avoid because they cause trouble in MySQL:
+ Double quoted identifiers: SELECT "MY COLUMN" from "MY TABLE"...
+ The string concatenation operator ||
+ Subselects
SQL-92 standard things to avoid because they cause trouble in PostgreSQL:
+ Outer joins.
+ "table1 JOIN table2" syntax; use WHERE clause joins instead.
Non-standard features used, available in both PostgreSQL and MySQL (this
information is provided for anyone attempting to port MRBS to another
database system):
+ MySQL implicitly assigns "DEFAULT current_timestamp" to a timestamp
column; this must be done explicitly in other database systems.
+ The column called TIMESTAMP is not legal in SQL-92. It would be legal
if double-quoted in SQL statements, but MySQL doesn't like that.
Changing the column name would break existing databases, and it turns
out both PostgreSQL and MySQL accept this, so it has been kept.
+ Auto-commit is assumed. The database wrappers have begin/end calls to
bracket transactions, but MRBS generally uses them only to improve
performance with grouped inserts/deletes/updates. It is assumed that
a single insert/delete/update SQL statement commits right away. If
a database doesn't implement this, it may be possible to incorporate
this into sql_command(), which is used for all data modification.
+ Portable use of auto-incrementing fields (PostgreSQL SERIAL, MySQL
AUTO_INCREMENT) requires that:
* Only one auto-increment field allowed per table; must be primary key.
* Use sql_insert_id() to retrieve the value after INSERT.
* Don't assume the value will either be MAX(field)+1, like MySQL,
or always incremented, like PostgreSQL. These can be different
when records have been deleted.
-----------------------------------------------------------------------------
The database class methods are documented here:
To make a new connection to a database, use the method DBFactory::create(), as:
DBFactory::create($db_system,
$db_host,
$db_username,
$db_password,
$db_name,
$persist = 0,
$db_port = null)
Here $db_system is either 'mysql' or 'pgsql' and $db_name is the name of
the database to access. This method returns an object of the class "DB".
The "DB" class has the following object methods:
->command($sql, $params)
Execute a non-SELECT SQL command (for example: insert, update, delete).
Returns the number of tuples affected if OK (a number >= 0).
Raises a "DBException" exception on error.
->query($sql, $params)
Execute an SQL query. Returns an object of class "DBStatement" (see methods further below).
->query1($sql, $params)
Execute an SQL query which should return a single non-negative number value.
Returns the value of the single column in the single row of the query |
result or -1 if the query returns no result, or a single NULL value, such as from
a MIN or MAX aggregate function applied over no rows.
Raises a "DBException" exception on error.
This is a short-cut alternative to ->query(), good for use with count(*)
and similar queries.
->insert_id($table, $fieldname)
Return the value of an autoincrement/serial field from the last insert.
This must be called right after the insert on that table. The $fieldname
is the name of the autoincrement or serial field in the table. The
return result will be correct even if other processes are updating the
database at the same time.
NOTE: To make this work with different DBMS's, the field name must be
specified, and it must name the only autoincrement/serial field in the
row inserted by the most recent INSERT.
->error()
Return the text of the last error message.
->begin()
Begin a transaction, if the database supports it. This is used to
improve performance for multiple insert/delete/updates on databases
which support transactions, and using it is not required. Do
not attempt to have both ->begin() and ->mutex_lock() active since
then both may be implemented with a shared underlying mechanism.
->commit()
Commit (end) a transaction. See ->begin().
->rollback()
Rollback a transaction. See ->begin().
->mutex_lock($name)
Acquire a mutual-exclusion lock on the named table. For portability:
* This will not lock out SELECTs.
* It may lock out DELETE/UPDATE/INSERT or it may not.
* It will lock out other callers of this routine with the same name
argument (which is the main reason for using it).
* It may timeout in 20 seconds and return 0, or may wait forever.
* It returns 1 when the lock has been acquired.
* Caller must release the lock with sql_mutex_unlock().
* Caller must not have more than one mutex lock at any time.
You should be sure to release the lock with sql_mutex_unlock() before the
script exits, although this function also establishes a shutdown handler to
automatically release the lock if the script exits. (With persistent
connections, the locks would not otherwise be released on exit, and a
deadlock will occur.)
This call effectively calls ->begin(), so do not use it inside an
->begin()/->end() block, nor use ->begin() between calls to
->mutex_lock() and ->mutex_unlock().
->mutex_unlock($name)
Release a mutual-exclusion lock on the named table. See ->mutex_lock().
This also effectively calls ->commit().
->version()
Return a string identifying the database system and version.
-----------------------------------------------------------------------------
The following ->syntax_* methods are intended to help you build up SQL
statements using non-standard features. Each returns a portion of SQL (with
leading and trailing spaces) which implements the named non-standard feature
for the selected database. Some methods must also be passed (by reference) an
array object for building the SQL parameters to pass to the query/command method.
->syntax_limit($count, $offset)
Generate non-standard SQL for LIMIT clauses, to make the query return
no more than $count records, starting at position $offset (basis 0).
->syntax_timestamp_to_unix($fieldname)
Generate non-standard SQL to output a TIMESTAMP as a Unix time_t. The
argument must be the name of a timestamp field.
->syntax_caseless_contains($fieldname, $s, &$params)
Generate a non-standard SQL predicate clause which will be true if the
string $s is contained anywhere in the named field, using case insensitive
string compare. This uses LIKE or Regular Expression matching, depending
on the database system. This method modifies the passed $params array
to add the appropriate SQL parameters.
->syntax_casesensitive_equals($fieldname, $string, &$params)
Generates a non-standard SQL predicate clause for a case-sensitive equals.
This method modifies the passed $params array to add the appropriate
SQL parameters.
->syntax_addcolumn_after($fieldname)
Generate non-standard SQL to add a table column after another specified
column.
->syntax_createtable_autoincrementcolumn()
Generate non-standard SQL to specify a column as an auto-incrementing
integer while doing a CREATE TABLE.
->syntax_bitwise_xor()
Returns the syntax for a bitwise XOR operator.
Example usage:
$sql = "SELECT * FROM mytable ORDER BY id" . $db_obj->syntax_limit(100,20);
With PostgreSQL this gives you:
$sql = "SELECT * FROM mytable ORDER BY id LIMIT 100 OFFSET 20";
With MySQL this gives you:
$sql = "SELECT * FROM mytable ORDER BY id LIMIT 20,100";
-----------------------------------------------------------------------------
DBStatement methods:
->row($rownumber)
Return a row from a result. The first row is row number 0.
The row is returned as an array with index 0=first column, etc.
When called with i >= number of rows in the result, returns 0 to signify
the end of the result set. This is designed to be used in a loop
like this to retrieve all the rows:
for ($i = 0; (($row = $stmt->row($r, $i)); $i++) { ... process the row ... }
->row_keyed($rownumber)
Return a row from a result. The first row is row number 0.
The row is returned as an associative array with column (field) names as
the indexes. (PHP also makes numeric indexes for the same data.)
When called with i >= number of rows in the result, returns 0 to signify
the end of the result set. This is designed to be used in a loop
like this to retrieve all the rows:
for ($i = 0; (($row = $stmt->row_keyed($i)); $i++) { ... }
NOTE: You should explicitly name each column in your SQL statement which
is not a simple field name, because databases differ in how they assume
a default name. For example, don't use ->row_keyed() on a query
like: SELECT name, COUNT(*) FROM ...
Instead use: SELECT name, COUNT(*) AS totals FROM ...
so you can reliably refer to the count as row["totals"].
->all_rows_keyed
Return all the rows from a statement object, as an array of arrays
keyed on the column name.
->count()
Returns the number of rows returned by the statement.
->num_fields()
Returns the number of columns/fields returned by the statement.