Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
Q
question2answer
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
outils
question2answer
Commits
adc56dfb
Commit
adc56dfb
authored
Jan 28, 2014
by
Scott
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Switch to mysqli
parent
fedbc59d
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
139 additions
and
128 deletions
+139
-128
qa-config-example.php
qa-config-example.php
+9
-4
qa-db.php
qa-include/qa-db.php
+130
-124
No files found.
qa-config-example.php
View file @
adc56dfb
...
...
@@ -28,9 +28,14 @@
======================================================================
THE 4 DEFINITIONS BELOW ARE REQUIRED AND MUST BE SET BEFORE USING!
======================================================================
For QA_MYSQL_HOSTNAME, try '127.0.0.1' or 'localhost' if MySQL is on the same server.
For persistent connections, set the QA_PERSISTENT_CONN_DB at the bottom of this file; do NOT
prepend the hostname with 'p:'.
*/
define
(
'QA_MYSQL_HOSTNAME'
,
'127.0.0.1'
);
// try '127.0.0.1' or 'localhost' if MySQL on same server
define
(
'QA_MYSQL_HOSTNAME'
,
'127.0.0.1'
);
define
(
'QA_MYSQL_USERNAME'
,
'your-mysql-username'
);
define
(
'QA_MYSQL_PASSWORD'
,
'your-mysql-password'
);
define
(
'QA_MYSQL_DATABASE'
,
'your-mysql-db-name'
);
...
...
@@ -151,9 +156,9 @@
create significant latency. This will minimize the number of database queries as much as
is possible, even at the cost of significant additional processing at each end.
Set QA_PERSISTENT_CONN_DB to true to use persistent database connections.
Only use this if
you are absolutely sure it is a good idea under your setup - generally it is not.
For more information: http://www.php.net/manual/en/features.persistent-connections.php
Set QA_PERSISTENT_CONN_DB to true to use persistent database connections.
Requires PHP 5.3.
Only use this if you are absolutely sure it is a good idea under your setup - generally it is
not.
For more information: http://www.php.net/manual/en/features.persistent-connections.php
Set QA_DEBUG_PERFORMANCE to true to show detailed performance profiling information at the
bottom of every Question2Answer page.
...
...
qa-include/qa-db.php
View file @
adc56dfb
...
...
@@ -46,7 +46,8 @@
function
qa_db_connect
(
$failhandler
=
null
)
/*
Connect to the Q2A database, select the right database, optionally install the $failhandler (and call it if necessary)
Connect to the Q2A database, select the right database, optionally install the $failhandler (and call it if necessary).
Uses mysqli as of Q2A 1.6.4.
*/
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
...
...
@@ -57,41 +58,35 @@
qa_fatal_error
(
'It appears that a plugin is trying to access the database, but this is not allowed until Q2A initialization is complete.'
);
if
(
isset
(
$failhandler
))
$qa_db_fail_handler
=
$failhandler
;
// set this even if connection already opened
$qa_db_fail_handler
=
$failhandler
;
// set this even if connection already opened
if
(
!
is_resource
(
$qa_db_connection
))
{
if
(
QA_PERSISTENT_CONN_DB
)
$db
=
mysql_pconnect
(
QA_FINAL_MYSQL_HOSTNAME
,
QA_FINAL_MYSQL_USERNAME
,
QA_FINAL_MYSQL_PASSWORD
);
else
$db
=
mysql_connect
(
QA_FINAL_MYSQL_HOSTNAME
,
QA_FINAL_MYSQL_USERNAME
,
QA_FINAL_MYSQL_PASSWORD
);
if
(
$qa_db_connection
instanceof
mysqli
)
return
;
if
(
is_resource
(
$db
))
{
if
(
!
mysql_select_db
(
QA_FINAL_MYSQL_DATABASE
,
$db
))
{
mysql_close
(
$db
);
qa_db_fail_error
(
'select'
);
}
// in mysqli we connect and select database in constructor
if
(
QA_PERSISTENT_CONN_DB
)
$db
=
new
mysqli
(
'p:'
.
QA_FINAL_MYSQL_HOSTNAME
,
QA_FINAL_MYSQL_USERNAME
,
QA_FINAL_MYSQL_PASSWORD
,
QA_FINAL_MYSQL_DATABASE
);
else
$db
=
new
mysqli
(
QA_FINAL_MYSQL_HOSTNAME
,
QA_FINAL_MYSQL_USERNAME
,
QA_FINAL_MYSQL_PASSWORD
,
QA_FINAL_MYSQL_DATABASE
);
/*
From Q2A 1.5, we *do* explicitly set the character encoding of the MySQL connection, instead
of using lots of "SELECT BINARY col AS col"-style queries, as in previous versions of Q2A.
Although this introduces the latency of another query here, testing showed that the delay is
the same as that from calling mysql_select_db() and only a quarter of that of mysql_connect().
So overall it adds 20% to the latency delay in qa_db_connect(), and this seems worth trading
off against the benefit of more straightforward queries, especially for plugin developers.
*/
// must use procedural `mysqli_connect_error` here prior to 5.2.9
$conn_error
=
mysqli_connect_error
();
if
(
$conn_error
)
qa_db_fail_error
(
'connect'
,
$db
->
connect_errno
,
$conn_error
);
if
(
function_exists
(
'mysql_set_charset'
))
mysql_set_charset
(
'utf8'
,
$db
);
else
mysql_query
(
'SET NAMES utf8'
,
$db
);
/*
From Q2A 1.5, we explicitly set the character encoding of the MySQL connection, instead of
using lots of "SELECT BINARY col"-style queries. Testing showed that overhead is minimal,
so this seems worth trading off against the benefit of more straightforward queries,
especially for plugin developers.
*/
qa_report_process_stage
(
'db_connected'
);
if
(
!
$db
->
set_charset
(
'utf8'
))
qa_db_fail_error
(
'set_charset'
,
$db
->
errno
,
$db
->
error
);
}
else
qa_db_fail_error
(
'connect'
);
qa_report_process_stage
(
'db_connected'
);
$qa_db_connection
=
$db
;
}
$qa_db_connection
=
$db
;
}
...
...
@@ -125,10 +120,10 @@
global
$qa_db_connection
;
if
(
$connect
&&
!
is_resource
(
$qa_db_connection
))
{
if
(
$connect
&&
!
(
$qa_db_connection
instanceof
mysqli
))
{
qa_db_connect
();
if
(
!
is_resource
(
$qa_db_connection
))
if
(
!
(
$qa_db_connection
instanceof
mysqli
))
qa_fatal_error
(
'Failed to connect to database'
);
}
...
...
@@ -145,12 +140,13 @@
global
$qa_db_connection
;
if
(
is_resource
(
$qa_db_connection
)
)
{
if
(
$qa_db_connection
instanceof
mysqli
)
{
qa_report_process_stage
(
'db_disconnect'
);
if
(
!
QA_PERSISTENT_CONN_DB
)
if
(
!
mysql_close
(
$qa_db_connection
))
if
(
!
QA_PERSISTENT_CONN_DB
)
{
if
(
!
$qa_db_connection
->
close
(
))
qa_fatal_error
(
'Database disconnect failed'
);
}
$qa_db_connection
=
null
;
}
...
...
@@ -168,34 +164,41 @@
if
(
QA_DEBUG_PERFORMANCE
)
{
global
$qa_database_usage
,
$qa_database_queries
;
$oldtime
=
array_sum
(
explode
(
' '
,
microtime
()));
$result
=
qa_db_query_execute
(
$query
);
$usedtime
=
array_sum
(
explode
(
' '
,
microtime
()))
-
$oldtime
;
$oldtime
=
array_sum
(
explode
(
' '
,
microtime
()));
$result
=
qa_db_query_execute
(
$query
);
$usedtime
=
array_sum
(
explode
(
' '
,
microtime
()))
-
$oldtime
;
if
(
is_array
(
$qa_database_usage
))
{
$qa_database_usage
[
'clock'
]
+=
$usedtime
;
if
(
strlen
(
$qa_database_queries
)
<
1048576
)
{
// don't keep track of big tests
$gotrows
=
is_resource
(
$result
)
?
mysql_num_rows
(
$result
)
:
null
;
$gotcolumns
=
is_resource
(
$result
)
?
mysql_num_fields
(
$result
)
:
null
;
$qa_database_queries
.=
$query
.
"
\n\n
"
.
sprintf
(
'%.2f ms'
,
$usedtime
*
1000
)
.
(
is_numeric
(
$gotrows
)
?
(
' - '
.
$gotrows
.
((
$gotrows
==
1
)
?
' row'
:
' rows'
))
:
''
)
.
(
is_numeric
(
$gotcolumns
)
?
(
' - '
.
$gotcolumns
.
((
$gotcolumns
==
1
)
?
' column'
:
' columns'
))
:
''
)
.
"
\n\n
"
;
$qa_database_usage
[
'clock'
]
+=
$usedtime
;
if
(
strlen
(
$qa_database_queries
)
<
1048576
)
{
// don't keep track of big tests
$gotrows
=
$gotcolumns
=
null
;
if
(
$result
instanceof
mysqli_result
)
{
$gotrows
=
$result
->
num_rows
;
$gotcolumns
=
$result
->
field_count
;
}
$rowcolstring
=
''
;
if
(
is_numeric
(
$gotrows
))
$rowcolstring
.=
' - '
.
$gotrows
.
(
$gotrows
==
1
?
' row'
:
' rows'
);
if
(
is_numeric
(
$gotcolumns
))
$rowcolstring
.=
' - '
.
$gotcolumns
.
(
$gotcolumns
==
1
?
' column'
:
' columns'
);
$qa_database_queries
.=
$query
.
"
\n\n
"
.
sprintf
(
'%.2f ms'
,
$usedtime
*
1000
)
.
$rowcolstring
.
"
\n\n
"
;
}
$qa_database_usage
[
'queries'
]
++
;
}
}
else
$result
=
qa_db_query_execute
(
$query
);
}
else
$result
=
qa_db_query_execute
(
$query
);
// @error_log('Question2Answer MySQL query: '.$query);
if
(
$result
===
false
)
{
$db
=
qa_db_connection
();
qa_db_fail_error
(
'query'
,
mysql_errno
(
$db
),
mysql_error
(
$db
)
,
$query
);
if
(
$result
===
false
)
{
$db
=
qa_db_connection
();
qa_db_fail_error
(
'query'
,
$db
->
errno
,
$db
->
error
,
$query
);
}
return
$result
;
...
...
@@ -209,13 +212,13 @@
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
$db
=
qa_db_connection
();
$db
=
qa_db_connection
();
for
(
$attempt
=
0
;
$attempt
<
100
;
$attempt
++
)
{
$result
=
mysql_query
(
$query
,
$db
);
for
(
$attempt
=
0
;
$attempt
<
100
;
$attempt
++
)
{
$result
=
$db
->
query
(
$query
);
if
(
(
$result
===
false
)
&&
(
mysql_errno
(
$db
)
==
1213
)
)
usleep
(
10000
);
// dea
d
with InnoDB deadlock errors by waiting 0.01s then retrying
if
(
$result
===
false
&&
$db
->
errno
==
1213
)
usleep
(
10000
);
// dea
l
with InnoDB deadlock errors by waiting 0.01s then retrying
else
break
;
}
...
...
@@ -231,7 +234,8 @@
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
return
mysql_real_escape_string
(
$string
,
qa_db_connection
());
$db
=
qa_db_connection
();
return
$db
->
real_escape_string
(
$string
);
}
...
...
@@ -245,21 +249,22 @@
$parts
=
array
();
foreach
(
$argument
as
$subargument
)
$parts
[]
=
qa_db_argument_to_mysql
(
$subargument
,
$alwaysquote
,
true
);
$parts
[]
=
qa_db_argument_to_mysql
(
$subargument
,
$alwaysquote
,
true
);
if
(
$arraybrackets
)
$result
=
'('
.
implode
(
','
,
$parts
)
.
')'
;
$result
=
'('
.
implode
(
','
,
$parts
)
.
')'
;
else
$result
=
implode
(
','
,
$parts
);
$result
=
implode
(
','
,
$parts
);
}
elseif
(
isset
(
$argument
))
{
}
else
if
(
isset
(
$argument
))
{
if
(
$alwaysquote
||
!
is_numeric
(
$argument
))
$result
=
"'"
.
qa_db_escape_string
(
$argument
)
.
"'"
;
$result
=
"'"
.
qa_db_escape_string
(
$argument
)
.
"'"
;
else
$result
=
qa_db_escape_string
(
$argument
);
}
else
$result
=
'NULL'
;
$result
=
qa_db_escape_string
(
$argument
);
}
else
$result
=
'NULL'
;
return
$result
;
}
...
...
@@ -272,7 +277,7 @@
{
if
(
qa_to_override
(
__FUNCTION__
))
{
$args
=
func_get_args
();
return
qa_call_override
(
__FUNCTION__
,
$args
);
}
$prefix
=
QA_MYSQL_TABLE_PREFIX
;
$prefix
=
QA_MYSQL_TABLE_PREFIX
;
if
(
defined
(
'QA_MYSQL_USERS_PREFIX'
))
{
switch
(
strtolower
(
$rawname
))
{
...
...
@@ -286,7 +291,7 @@
case
'cache'
:
case
'userlogins_ibfk_1'
:
// also special cases for constraint names
case
'userprofile_ibfk_1'
:
$prefix
=
QA_MYSQL_USERS_PREFIX
;
$prefix
=
QA_MYSQL_USERS_PREFIX
;
break
;
}
}
...
...
@@ -313,32 +318,33 @@
It's important to use $ when matching a textual column since MySQL won't use indexes to compare text against numbers.
*/
{
$query
=
preg_replace_callback
(
'/\^([A-Za-z_0-9]+)/'
,
'qa_db_prefix_callback'
,
$query
);
$query
=
preg_replace_callback
(
'/\^([A-Za-z_0-9]+)/'
,
'qa_db_prefix_callback'
,
$query
);
if
(
is_array
(
$arguments
))
{
$countargs
=
count
(
$arguments
);
$offset
=
0
;
if
(
!
is_array
(
$arguments
))
return
$query
;
for
(
$argument
=
0
;
$argument
<
$countargs
;
$argument
++
)
{
$stringpos
=
strpos
(
$query
,
'$'
,
$offset
);
$numberpos
=
strpos
(
$query
,
'#'
,
$offset
);
$countargs
=
count
(
$arguments
);
$offset
=
0
;
if
(
(
$stringpos
===
false
)
||
(
(
$numberpos
!==
false
)
&&
(
$numberpos
<
$stringpos
)
)
)
{
$alwaysquote
=
false
;
$position
=
$numberpos
;
for
(
$argument
=
0
;
$argument
<
$countargs
;
$argument
++
)
{
$stringpos
=
strpos
(
$query
,
'$'
,
$offset
)
;
$numberpos
=
strpos
(
$query
,
'#'
,
$offset
)
;
}
else
{
$alwaysquote
=
true
;
$position
=
$stringpos
;
}
if
(
$stringpos
===
false
||
(
$numberpos
!==
false
&&
$numberpos
<
$stringpos
))
{
$alwaysquote
=
false
;
$position
=
$numberpos
;
}
else
{
$alwaysquote
=
true
;
$position
=
$stringpos
;
}
if
(
!
is_numeric
(
$position
))
qa_fatal_error
(
'Insufficient parameters in query: '
.
$query
);
if
(
!
is_numeric
(
$position
))
qa_fatal_error
(
'Insufficient parameters in query: '
.
$query
);
$value
=
qa_db_argument_to_mysql
(
$arguments
[
$argument
],
$alwaysquote
);
$query
=
substr_replace
(
$query
,
$value
,
$position
,
1
);
$offset
=
$position
+
strlen
(
$value
);
// allows inserting strings which contain #/$ character
}
$value
=
qa_db_argument_to_mysql
(
$arguments
[
$argument
],
$alwaysquote
);
$query
=
substr_replace
(
$query
,
$value
,
$position
,
1
);
$offset
=
$position
+
strlen
(
$value
);
// allows inserting strings which contain #/$ character
}
return
$query
;
...
...
@@ -361,7 +367,8 @@
Return the value of the auto-increment column for the last inserted row
*/
{
return
qa_db_read_one_value
(
qa_db_query_raw
(
'SELECT LAST_INSERT_ID()'
));
$db
=
qa_db_connection
();
return
$db
->
insert_id
;
}
...
...
@@ -370,7 +377,8 @@
Does what it says on the tin
*/
{
return
mysql_affected_rows
(
qa_db_connection
());
$db
=
qa_db_connection
();
return
$db
->
affected_rows
;
}
...
...
@@ -379,7 +387,7 @@
For the previous INSERT ... ON DUPLICATE KEY UPDATE query, return whether an insert operation took place
*/
{
return
(
qa_db_affected_rows
()
==
1
);
return
(
qa_db_affected_rows
()
==
1
);
}
...
...
@@ -462,12 +470,12 @@
Return the data specified by a single $selectspec - see long comment above.
*/
{
$query
=
'SELECT '
;
$query
=
'SELECT '
;
foreach
(
$selectspec
[
'columns'
]
as
$columnas
=>
$columnfrom
)
$query
.=
$columnfrom
.
(
is_int
(
$columnas
)
?
''
:
(
' AS '
.
$columnas
))
.
', '
;
$query
.=
$columnfrom
.
(
is_int
(
$columnas
)
?
''
:
(
' AS '
.
$columnas
))
.
', '
;
$results
=
qa_db_read_all_assoc
(
qa_db_query_raw
(
qa_db_apply_sub
(
$results
=
qa_db_read_all_assoc
(
qa_db_query_raw
(
qa_db_apply_sub
(
substr
(
$query
,
0
,
-
2
)
.
(
strlen
(
@
$selectspec
[
'source'
])
?
(
' FROM '
.
$selectspec
[
'source'
])
:
''
),
@
$selectspec
[
'arguments'
])
),
@
$selectspec
[
'arraykey'
]);
// arrayvalue is applied in qa_db_post_select()
...
...
@@ -639,16 +647,16 @@
is from column $value if specified, otherwise it's a named array of all columns, given an array of arrays.
*/
{
if
(
!
is_resource
(
$
result
))
if
(
!
(
$result
instanceof
mysqli_
result
))
qa_fatal_error
(
'Reading all assoc from invalid result'
);
$assocs
=
array
();
$assocs
=
array
();
while
(
$assoc
=
mysql_fetch_assoc
(
$result
))
{
while
(
$assoc
=
$result
->
fetch_assoc
(
))
{
if
(
isset
(
$key
))
$assocs
[
$assoc
[
$key
]]
=
isset
(
$value
)
?
$assoc
[
$value
]
:
$assoc
;
$assocs
[
$assoc
[
$key
]]
=
isset
(
$value
)
?
$assoc
[
$value
]
:
$assoc
;
else
$assocs
[]
=
isset
(
$value
)
?
$assoc
[
$value
]
:
$assoc
;
$assocs
[]
=
isset
(
$value
)
?
$assoc
[
$value
]
:
$assoc
;
}
return
$assocs
;
...
...
@@ -661,19 +669,18 @@
If there's no first row, throw a fatal error unless $allowempty is true.
*/
{
if
(
!
is_resource
(
$
result
))
if
(
!
(
$result
instanceof
mysqli_
result
))
qa_fatal_error
(
'Reading one assoc from invalid result'
);
$assoc
=
mysql_fetch_assoc
(
$result
);
$assoc
=
$result
->
fetch_assoc
(
);
if
(
!
is_array
(
$assoc
))
{
if
(
$allowempty
)
return
null
;
else
qa_fatal_error
(
'Reading one assoc from empty results'
);
}
if
(
is_array
(
$assoc
))
return
$assoc
;
return
$assoc
;
if
(
$allowempty
)
return
null
;
else
qa_fatal_error
(
'Reading one assoc from empty results'
);
}
...
...
@@ -682,13 +689,13 @@
Return a numbered array containing the first (and presumably only) column from the $result resource
*/
{
if
(
!
is_resource
(
$
result
))
if
(
!
(
$result
instanceof
mysqli_
result
))
qa_fatal_error
(
'Reading column from invalid result'
);
$output
=
array
();
$output
=
array
();
while
(
$row
=
mysql_fetch_row
(
$result
))
$output
[]
=
$row
[
0
];
while
(
$row
=
$result
->
fetch_row
(
))
$output
[]
=
$row
[
0
];
return
$output
;
}
...
...
@@ -700,19 +707,18 @@
If there's no first row, throw a fatal error unless $allowempty is true.
*/
{
if
(
!
is_resource
(
$
result
))
if
(
!
(
$result
instanceof
mysqli_
result
))
qa_fatal_error
(
'Reading one value from invalid result'
);
$row
=
mysql_fetch_row
(
$result
);
$row
=
$result
->
fetch_row
(
);
if
(
!
is_array
(
$row
))
{
if
(
$allowempty
)
return
null
;
else
qa_fatal_error
(
'Reading one value from empty results'
);
}
if
(
is_array
(
$row
))
return
$row
[
0
];
return
$row
[
0
];
if
(
$allowempty
)
return
null
;
else
qa_fatal_error
(
'Reading one value from empty results'
);
}
...
...
@@ -724,7 +730,7 @@
{
global
$qa_update_counts_suspended
;
$qa_update_counts_suspended
+=
(
$suspend
?
1
:
-
1
);
$qa_update_counts_suspended
+=
(
$suspend
?
1
:
-
1
);
}
...
...
@@ -735,7 +741,7 @@
{
global
$qa_update_counts_suspended
;
return
(
$qa_update_counts_suspended
<=
0
);
return
(
$qa_update_counts_suspended
<=
0
);
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment