Enforce mxRowHeight in columnar layouts. Code clean-up. Minimum column with
is 2 if there is wrapping, in case there are double-wide characters. FossilOrigin-Name: 0ee8fc00af4c82da0d597c65dd3d8590c71ea78d8f4a29653bbb21668c6c530d
This commit is contained in:
482
ext/qrf/qrf.c
482
ext/qrf/qrf.c
@@ -52,6 +52,8 @@ struct Qrf {
|
||||
int iErr; /* Error code */
|
||||
int nCol; /* Number of output columns */
|
||||
int expMode; /* Original sqlite3_stmt_isexplain() plus 1 */
|
||||
int mxWidth; /* Screen width */
|
||||
int mxHeight; /* mxRowHeight */
|
||||
union {
|
||||
struct { /* Content for QRF_STYLE_Line */
|
||||
int mxColWth; /* Maximum display width of any column */
|
||||
@@ -1243,6 +1245,36 @@ static void qrfLoadAlignment(qrfColData *pData, Qrf *p){
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Output horizontally justified text into pOut. The text is the
|
||||
** first nVal bytes of zVal. Include nWS bytes of whitespace, either
|
||||
** split between both sides, or on the left, or on the right, depending
|
||||
** on eAlign.
|
||||
*/
|
||||
static void qrfPrintAligned(
|
||||
sqlite3_str *pOut, /* Append text here */
|
||||
const char *zVal, /* Text to append */
|
||||
int nVal, /* Use only the first nVal bytes of zVal[] */
|
||||
int nWS, /* Whitespace for horizonal alignment */
|
||||
unsigned char eAlign /* Alignment type */
|
||||
){
|
||||
eAlign &= QRF_ALIGN_HMASK;
|
||||
if( eAlign==QRF_ALIGN_Center ){
|
||||
/* Center the text */
|
||||
sqlite3_str_appendchar(pOut, nWS/2, ' ');
|
||||
sqlite3_str_append(pOut, zVal, nVal);
|
||||
sqlite3_str_appendchar(pOut, nWS - nWS/2, ' ');
|
||||
}else if( eAlign==QRF_ALIGN_Right){
|
||||
/* Right justify the text */
|
||||
sqlite3_str_appendchar(pOut, nWS, ' ');
|
||||
sqlite3_str_append(pOut, zVal, nVal);
|
||||
}else{
|
||||
/* Left justify the next */
|
||||
sqlite3_str_append(pOut, zVal, nVal);
|
||||
sqlite3_str_appendchar(pOut, nWS, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Columnar modes require that the entire query be evaluated first, with
|
||||
** results written into memory, so that we can compute appropriate column
|
||||
@@ -1357,10 +1389,15 @@ static void qrfColumnar(Qrf *p){
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if( data.bMultiRow==0 ){
|
||||
}else if( data.bMultiRow==0 || w==1 ){
|
||||
for(j=i; j<data.n; j+=nColumn){
|
||||
if( data.aiWth[j] > w ){
|
||||
data.bMultiRow = 1;
|
||||
if( w==1 ){
|
||||
/* If aiWth[j] is 2 or more, then there might be a double-wide
|
||||
** character somewhere. So make the column width at least 2. */
|
||||
w = 2;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1403,6 +1440,7 @@ static void qrfColumnar(Qrf *p){
|
||||
bWW = (p->spec.bWordWrap==QRF_Yes && data.bMultiRow);
|
||||
for(i=0; i<data.n; i+=nColumn){
|
||||
int bMore;
|
||||
int nRow = 0;
|
||||
|
||||
/* Draw a single row of the table. This might be the title line
|
||||
** (if there is a title line) or a row in the body of the table.
|
||||
@@ -1419,20 +1457,7 @@ static void qrfColumnar(Qrf *p){
|
||||
int nWS;
|
||||
qrfWrapLine(data.azThis[j], data.aiCol[j], bWW, &nThis, &nWide, &iNext);
|
||||
nWS = data.aiCol[j] - nWide;
|
||||
if( (data.aAlign[j] & QRF_ALIGN_HMASK)==QRF_ALIGN_Center ){
|
||||
/* Center the text */
|
||||
sqlite3_str_appendchar(p->pOut, nWS/2, ' ');
|
||||
sqlite3_str_append(p->pOut, data.azThis[j], nThis);
|
||||
sqlite3_str_appendchar(p->pOut, nWS - nWS/2, ' ');
|
||||
}else if( (data.aAlign[j] & QRF_ALIGN_HMASK)==QRF_ALIGN_Right){
|
||||
/* Right justify the text */
|
||||
sqlite3_str_appendchar(p->pOut, nWS, ' ');
|
||||
sqlite3_str_append(p->pOut, data.azThis[j], nThis);
|
||||
}else{
|
||||
/* Left justify the next */
|
||||
sqlite3_str_append(p->pOut, data.azThis[j], nThis);
|
||||
sqlite3_str_appendchar(p->pOut, nWS, ' ');
|
||||
}
|
||||
qrfPrintAligned(p->pOut, data.azThis[j], nThis, nWS, data.aAlign[j]);
|
||||
data.azThis[j] += iNext;
|
||||
if( data.azThis[j][0]!=0 ) bMore = 1;
|
||||
if( j<nColumn-1 ){
|
||||
@@ -1441,7 +1466,25 @@ static void qrfColumnar(Qrf *p){
|
||||
sqlite3_str_append(p->pOut, rowSep, szRowSep);
|
||||
}
|
||||
}
|
||||
}while( bMore );
|
||||
}while( bMore && ++nRow < p->mxHeight );
|
||||
if( bMore ){
|
||||
/* This row was terminated by mxRowHeight. Show ellipsis. */
|
||||
sqlite3_str_append(p->pOut, rowStart, szRowStart);
|
||||
for(j=0; j<nColumn; j++){
|
||||
if( data.azThis[j][0]==0 ){
|
||||
sqlite3_str_appendchar(p->pOut, data.aiCol[j], ' ');
|
||||
}else{
|
||||
int nE = 3;
|
||||
if( nE>data.aiCol[j] ) nE = data.aiCol[j];
|
||||
qrfPrintAligned(p->pOut, "...", nE, data.aiCol[j]-nE, data.aAlign[j]);
|
||||
}
|
||||
if( j<nColumn-1 ){
|
||||
sqlite3_str_append(p->pOut, colSep, szColSep);
|
||||
}else{
|
||||
sqlite3_str_append(p->pOut, rowSep, szRowSep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw either (1) the separator between the title line and the body
|
||||
** of the table, or (2) separators between individual rows of the table
|
||||
@@ -1711,6 +1754,208 @@ static void qrfScanStatusVm(Qrf *p){
|
||||
p->pStmt = pOrigStmt;
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to determine if identifier zName needs to be quoted, either
|
||||
** because it contains non-alphanumeric characters, or because it is an
|
||||
** SQLite keyword. Be conservative in this estimate: When in doubt assume
|
||||
** that quoting is required.
|
||||
**
|
||||
** Return 1 if quoting is required. Return 0 if no quoting is required.
|
||||
*/
|
||||
|
||||
static int qrf_need_quote(const char *zName){
|
||||
int i;
|
||||
const unsigned char *z = (const unsigned char*)zName;
|
||||
if( z==0 ) return 1;
|
||||
if( !isalpha(z[0]) && z[0]!='_' ) return 1;
|
||||
for(i=0; z[i]; i++){
|
||||
if( !isalnum(z[i]) && z[i]!='_' ) return 1;
|
||||
}
|
||||
return sqlite3_keyword_check(zName, i)!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Helper function for QRF_STYLE_Json and QRF_STYLE_JsonLine.
|
||||
** The initial "{" for a JSON object that will contain row content
|
||||
** has been output. Now output all the content.
|
||||
*/
|
||||
static void qrfOneJsonRow(Qrf *p){
|
||||
int i, nItem;
|
||||
for(nItem=i=0; i<p->nCol; i++){
|
||||
const char *zCName;
|
||||
if( sqlite3_column_type(p->pStmt,i)==SQLITE_NULL ) continue;
|
||||
zCName = sqlite3_column_name(p->pStmt, i);
|
||||
if( nItem>0 ) sqlite3_str_append(p->pOut, ",", 1);
|
||||
nItem++;
|
||||
qrfEncodeText(p, p->pOut, zCName);
|
||||
sqlite3_str_append(p->pOut, ":", 1);
|
||||
qrfRenderValue(p, p->pOut, i);
|
||||
}
|
||||
qrfWrite(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Render a single row of output for non-columnar styles - any
|
||||
** style that lets us render row by row as the content is received
|
||||
** from the query.
|
||||
*/
|
||||
static void qrfOneSimpleRow(Qrf *p){
|
||||
int i;
|
||||
switch( p->spec.eStyle ){
|
||||
case QRF_STYLE_Off:
|
||||
case QRF_STYLE_Count: {
|
||||
/* No-op */
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Json: {
|
||||
if( p->nRow==0 ){
|
||||
sqlite3_str_append(p->pOut, "[{", 2);
|
||||
}else{
|
||||
sqlite3_str_append(p->pOut, "},\n{", 4);
|
||||
}
|
||||
qrfOneJsonRow(p);
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_JsonLine: {
|
||||
if( p->nRow==0 ){
|
||||
sqlite3_str_append(p->pOut, "{", 1);
|
||||
}else{
|
||||
sqlite3_str_append(p->pOut, "}\n{", 3);
|
||||
}
|
||||
qrfOneJsonRow(p);
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Html: {
|
||||
if( p->nRow==0 && p->spec.bColumnNames==QRF_Yes ){
|
||||
sqlite3_str_append(p->pOut, "<TR>", 4);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
const char *zCName = sqlite3_column_name(p->pStmt, i);
|
||||
sqlite3_str_append(p->pOut, "\n<TH>", 5);
|
||||
qrfEncodeText(p, p->pOut, zCName);
|
||||
}
|
||||
sqlite3_str_append(p->pOut, "\n</TR>\n", 7);
|
||||
}
|
||||
sqlite3_str_append(p->pOut, "<TR>", 4);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
sqlite3_str_append(p->pOut, "\n<TD>", 5);
|
||||
qrfRenderValue(p, p->pOut, i);
|
||||
}
|
||||
sqlite3_str_append(p->pOut, "\n</TR>\n", 7);
|
||||
qrfWrite(p);
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Insert: {
|
||||
if( qrf_need_quote(p->spec.zTableName) ){
|
||||
sqlite3_str_appendf(p->pOut,"INSERT INTO \"%w\"",p->spec.zTableName);
|
||||
}else{
|
||||
sqlite3_str_appendf(p->pOut,"INSERT INTO %s",p->spec.zTableName);
|
||||
}
|
||||
if( p->spec.bColumnNames==QRF_Yes ){
|
||||
for(i=0; i<p->nCol; i++){
|
||||
const char *zCName = sqlite3_column_name(p->pStmt, i);
|
||||
if( qrf_need_quote(zCName) ){
|
||||
sqlite3_str_appendf(p->pOut, "%c\"%w\"",
|
||||
i==0 ? '(' : ',', zCName);
|
||||
}else{
|
||||
sqlite3_str_appendf(p->pOut, "%c%s",
|
||||
i==0 ? '(' : ',', zCName);
|
||||
}
|
||||
}
|
||||
sqlite3_str_append(p->pOut, ")", 1);
|
||||
}
|
||||
sqlite3_str_append(p->pOut," VALUES(", 8);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
if( i>0 ) sqlite3_str_append(p->pOut, ",", 1);
|
||||
qrfRenderValue(p, p->pOut, i);
|
||||
}
|
||||
sqlite3_str_append(p->pOut, ");\n", 3);
|
||||
qrfWrite(p);
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Line: {
|
||||
sqlite3_str *pVal;
|
||||
int mxW;
|
||||
int bWW;
|
||||
if( p->u.sLine.azCol==0 ){
|
||||
p->u.sLine.azCol = sqlite3_malloc64( p->nCol*sizeof(char*) );
|
||||
if( p->u.sLine.azCol==0 ){
|
||||
qrfOom(p);
|
||||
break;
|
||||
}
|
||||
p->u.sLine.mxColWth = 0;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
int sz;
|
||||
p->u.sLine.azCol[i] = sqlite3_column_name(p->pStmt, i);
|
||||
if( p->u.sLine.azCol[i]==0 ) p->u.sLine.azCol[i] = "unknown";
|
||||
sz = qrfDisplayLength(p->u.sLine.azCol[i]);
|
||||
if( sz > p->u.sLine.mxColWth ) p->u.sLine.mxColWth = sz;
|
||||
}
|
||||
}
|
||||
if( p->nRow ) sqlite3_str_append(p->pOut, "\n", 1);
|
||||
pVal = sqlite3_str_new(p->db);
|
||||
mxW = p->mxWidth - (3 + p->u.sLine.mxColWth);
|
||||
bWW = p->spec.bWordWrap==QRF_Yes;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
const char *zVal;
|
||||
int cnt = 0;
|
||||
qrfWidthPrint(p, p->pOut, -p->u.sLine.mxColWth, p->u.sLine.azCol[i]);
|
||||
sqlite3_str_append(p->pOut, " = ", 3);
|
||||
qrfRenderValue(p, pVal, i);
|
||||
zVal = sqlite3_str_value(pVal);
|
||||
if( zVal==0 ) zVal = "";
|
||||
do{
|
||||
int nThis, nWide, iNext;
|
||||
qrfWrapLine(zVal, mxW, bWW, &nThis, &nWide, &iNext);
|
||||
if( cnt ) sqlite3_str_appendchar(p->pOut,p->u.sLine.mxColWth+3,' ');
|
||||
cnt++;
|
||||
if( cnt>p->mxHeight ){
|
||||
zVal = "...";
|
||||
nThis = iNext = 3;
|
||||
}
|
||||
sqlite3_str_append(p->pOut, zVal, nThis);
|
||||
sqlite3_str_append(p->pOut, "\n", 1);
|
||||
zVal += iNext;
|
||||
}while( zVal[0] );
|
||||
sqlite3_str_reset(pVal);
|
||||
}
|
||||
sqlite3_free(sqlite3_str_finish(pVal));
|
||||
qrfWrite(p);
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Eqp: {
|
||||
const char *zEqpLine = (const char*)sqlite3_column_text(p->pStmt,3);
|
||||
int iEqpId = sqlite3_column_int(p->pStmt, 0);
|
||||
int iParentId = sqlite3_column_int(p->pStmt, 1);
|
||||
if( zEqpLine==0 ) zEqpLine = "";
|
||||
if( zEqpLine[0]=='-' ) qrfEqpRender(p, 0);
|
||||
qrfEqpAppend(p, iEqpId, iParentId, zEqpLine);
|
||||
break;
|
||||
}
|
||||
default: { /* QRF_STYLE_List */
|
||||
if( p->nRow==0 && p->spec.bColumnNames==QRF_Yes ){
|
||||
int saved_eText = p->spec.eText;
|
||||
p->spec.eText = p->spec.eTitle;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
const char *zCName = sqlite3_column_name(p->pStmt, i);
|
||||
if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
|
||||
qrfEncodeText(p, p->pOut, zCName);
|
||||
}
|
||||
sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
|
||||
qrfWrite(p);
|
||||
p->spec.eText = saved_eText;
|
||||
}
|
||||
for(i=0; i<p->nCol; i++){
|
||||
if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
|
||||
qrfRenderValue(p, p->pOut, i);
|
||||
}
|
||||
sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
|
||||
qrfWrite(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p->nRow++;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize the internal Qrf object.
|
||||
*/
|
||||
@@ -1742,6 +1987,10 @@ static void qrfInitialize(
|
||||
sz = sizeof(sqlite3_qrf_spec);
|
||||
memcpy(&p->spec, pSpec, sz);
|
||||
if( p->spec.zNull==0 ) p->spec.zNull = "";
|
||||
p->mxWidth = p->spec.nScreenWidth;
|
||||
if( p->mxWidth<=0 ) p->mxWidth = QRF_MAX_WIDTH;
|
||||
p->mxHeight = p->spec.mxRowHeight;
|
||||
if( p->mxHeight<=0 ) p->mxHeight = 2147483647;
|
||||
qrf_reinit:
|
||||
switch( p->spec.eStyle ){
|
||||
case QRF_Auto: {
|
||||
@@ -1862,207 +2111,6 @@ qrf_reinit:
|
||||
if( p->spec.zRowSep==0 ) p->spec.zRowSep = "\n";
|
||||
}
|
||||
|
||||
/*
|
||||
** Attempt to determine if identifier zName needs to be quoted, either
|
||||
** because it contains non-alphanumeric characters, or because it is an
|
||||
** SQLite keyword. Be conservative in this estimate: When in doubt assume
|
||||
** that quoting is required.
|
||||
**
|
||||
** Return 1 if quoting is required. Return 0 if no quoting is required.
|
||||
*/
|
||||
|
||||
static int qrf_need_quote(const char *zName){
|
||||
int i;
|
||||
const unsigned char *z = (const unsigned char*)zName;
|
||||
if( z==0 ) return 1;
|
||||
if( !isalpha(z[0]) && z[0]!='_' ) return 1;
|
||||
for(i=0; z[i]; i++){
|
||||
if( !isalnum(z[i]) && z[i]!='_' ) return 1;
|
||||
}
|
||||
return sqlite3_keyword_check(zName, i)!=0;
|
||||
}
|
||||
|
||||
/*
|
||||
** Helper function for QRF_STYLE_Json and QRF_STYLE_JsonLine.
|
||||
** The initial "{" for a JSON object that will contain row content
|
||||
** has been output. Now output all the content.
|
||||
*/
|
||||
static void qrfOneJsonRow(Qrf *p){
|
||||
int i, nItem;
|
||||
for(nItem=i=0; i<p->nCol; i++){
|
||||
const char *zCName;
|
||||
if( sqlite3_column_type(p->pStmt,i)==SQLITE_NULL ) continue;
|
||||
zCName = sqlite3_column_name(p->pStmt, i);
|
||||
if( nItem>0 ) sqlite3_str_append(p->pOut, ",", 1);
|
||||
nItem++;
|
||||
qrfEncodeText(p, p->pOut, zCName);
|
||||
sqlite3_str_append(p->pOut, ":", 1);
|
||||
qrfRenderValue(p, p->pOut, i);
|
||||
}
|
||||
qrfWrite(p);
|
||||
}
|
||||
|
||||
/*
|
||||
** Render a single row of output.
|
||||
*/
|
||||
static void qrfOneSimpleRow(Qrf *p){
|
||||
int i;
|
||||
switch( p->spec.eStyle ){
|
||||
case QRF_STYLE_Off:
|
||||
case QRF_STYLE_Count: {
|
||||
/* No-op */
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Json: {
|
||||
if( p->nRow==0 ){
|
||||
sqlite3_str_append(p->pOut, "[{", 2);
|
||||
}else{
|
||||
sqlite3_str_append(p->pOut, "},\n{", 4);
|
||||
}
|
||||
qrfOneJsonRow(p);
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_JsonLine: {
|
||||
if( p->nRow==0 ){
|
||||
sqlite3_str_append(p->pOut, "{", 1);
|
||||
}else{
|
||||
sqlite3_str_append(p->pOut, "}\n{", 3);
|
||||
}
|
||||
qrfOneJsonRow(p);
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Html: {
|
||||
if( p->nRow==0 && p->spec.bColumnNames==QRF_Yes ){
|
||||
sqlite3_str_append(p->pOut, "<TR>", 4);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
const char *zCName = sqlite3_column_name(p->pStmt, i);
|
||||
sqlite3_str_append(p->pOut, "\n<TH>", 5);
|
||||
qrfEncodeText(p, p->pOut, zCName);
|
||||
}
|
||||
sqlite3_str_append(p->pOut, "\n</TR>\n", 7);
|
||||
}
|
||||
sqlite3_str_append(p->pOut, "<TR>", 4);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
sqlite3_str_append(p->pOut, "\n<TD>", 5);
|
||||
qrfRenderValue(p, p->pOut, i);
|
||||
}
|
||||
sqlite3_str_append(p->pOut, "\n</TR>\n", 7);
|
||||
qrfWrite(p);
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Insert: {
|
||||
if( qrf_need_quote(p->spec.zTableName) ){
|
||||
sqlite3_str_appendf(p->pOut,"INSERT INTO \"%w\"",p->spec.zTableName);
|
||||
}else{
|
||||
sqlite3_str_appendf(p->pOut,"INSERT INTO %s",p->spec.zTableName);
|
||||
}
|
||||
if( p->spec.bColumnNames==QRF_Yes ){
|
||||
for(i=0; i<p->nCol; i++){
|
||||
const char *zCName = sqlite3_column_name(p->pStmt, i);
|
||||
if( qrf_need_quote(zCName) ){
|
||||
sqlite3_str_appendf(p->pOut, "%c\"%w\"",
|
||||
i==0 ? '(' : ',', zCName);
|
||||
}else{
|
||||
sqlite3_str_appendf(p->pOut, "%c%s",
|
||||
i==0 ? '(' : ',', zCName);
|
||||
}
|
||||
}
|
||||
sqlite3_str_append(p->pOut, ")", 1);
|
||||
}
|
||||
sqlite3_str_append(p->pOut," VALUES(", 8);
|
||||
for(i=0; i<p->nCol; i++){
|
||||
if( i>0 ) sqlite3_str_append(p->pOut, ",", 1);
|
||||
qrfRenderValue(p, p->pOut, i);
|
||||
}
|
||||
sqlite3_str_append(p->pOut, ");\n", 3);
|
||||
qrfWrite(p);
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Line: {
|
||||
sqlite3_str *pVal;
|
||||
int mxW;
|
||||
int bWW;
|
||||
if( p->u.sLine.azCol==0 ){
|
||||
p->u.sLine.azCol = sqlite3_malloc64( p->nCol*sizeof(char*) );
|
||||
if( p->u.sLine.azCol==0 ){
|
||||
qrfOom(p);
|
||||
break;
|
||||
}
|
||||
p->u.sLine.mxColWth = 0;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
int sz;
|
||||
p->u.sLine.azCol[i] = sqlite3_column_name(p->pStmt, i);
|
||||
if( p->u.sLine.azCol[i]==0 ) p->u.sLine.azCol[i] = "unknown";
|
||||
sz = qrfDisplayLength(p->u.sLine.azCol[i]);
|
||||
if( sz > p->u.sLine.mxColWth ) p->u.sLine.mxColWth = sz;
|
||||
}
|
||||
}
|
||||
if( p->nRow ) sqlite3_str_append(p->pOut, "\n", 1);
|
||||
pVal = sqlite3_str_new(p->db);
|
||||
mxW = p->spec.nScreenWidth ? p->spec.nScreenWidth : QRF_MAX_WIDTH;
|
||||
mxW -= 3 + p->u.sLine.mxColWth;
|
||||
bWW = p->spec.bWordWrap==QRF_Yes;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
const char *zVal;
|
||||
int cnt = 0;
|
||||
qrfWidthPrint(p, p->pOut, -p->u.sLine.mxColWth, p->u.sLine.azCol[i]);
|
||||
sqlite3_str_append(p->pOut, " = ", 3);
|
||||
qrfRenderValue(p, pVal, i);
|
||||
zVal = sqlite3_str_value(pVal);
|
||||
if( zVal==0 ) zVal = "";
|
||||
do{
|
||||
int nThis, nWide, iNext;
|
||||
qrfWrapLine(zVal, mxW, bWW, &nThis, &nWide, &iNext);
|
||||
if( cnt ) sqlite3_str_appendchar(p->pOut,p->u.sLine.mxColWth+3,' ');
|
||||
cnt++;
|
||||
if( p->spec.mxRowHeight>0 && cnt>p->spec.mxRowHeight ){
|
||||
zVal = "...";
|
||||
nThis = iNext = 3;
|
||||
}
|
||||
sqlite3_str_append(p->pOut, zVal, nThis);
|
||||
sqlite3_str_append(p->pOut, "\n", 1);
|
||||
zVal += iNext;
|
||||
}while( zVal[0] );
|
||||
sqlite3_str_reset(pVal);
|
||||
}
|
||||
sqlite3_free(sqlite3_str_finish(pVal));
|
||||
qrfWrite(p);
|
||||
break;
|
||||
}
|
||||
case QRF_STYLE_Eqp: {
|
||||
const char *zEqpLine = (const char*)sqlite3_column_text(p->pStmt,3);
|
||||
int iEqpId = sqlite3_column_int(p->pStmt, 0);
|
||||
int iParentId = sqlite3_column_int(p->pStmt, 1);
|
||||
if( zEqpLine==0 ) zEqpLine = "";
|
||||
if( zEqpLine[0]=='-' ) qrfEqpRender(p, 0);
|
||||
qrfEqpAppend(p, iEqpId, iParentId, zEqpLine);
|
||||
break;
|
||||
}
|
||||
default: { /* QRF_STYLE_List */
|
||||
if( p->nRow==0 && p->spec.bColumnNames==QRF_Yes ){
|
||||
int saved_eText = p->spec.eText;
|
||||
p->spec.eText = p->spec.eTitle;
|
||||
for(i=0; i<p->nCol; i++){
|
||||
const char *zCName = sqlite3_column_name(p->pStmt, i);
|
||||
if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
|
||||
qrfEncodeText(p, p->pOut, zCName);
|
||||
}
|
||||
sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
|
||||
qrfWrite(p);
|
||||
p->spec.eText = saved_eText;
|
||||
}
|
||||
for(i=0; i<p->nCol; i++){
|
||||
if( i>0 ) sqlite3_str_appendall(p->pOut, p->spec.zColumnSep);
|
||||
qrfRenderValue(p, p->pOut, i);
|
||||
}
|
||||
sqlite3_str_appendall(p->pOut, p->spec.zRowSep);
|
||||
qrfWrite(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
p->nRow++;
|
||||
}
|
||||
|
||||
/*
|
||||
** Finish rendering the results
|
||||
*/
|
||||
|
||||
14
manifest
14
manifest
@@ -1,5 +1,5 @@
|
||||
C Fixes\sfor\sharmless\sstatic\sanalyzer\swarnings.
|
||||
D 2025-11-09T00:37:29.108
|
||||
C Enforce\smxRowHeight\sin\scolumnar\slayouts.\s\sCode\sclean-up.\s\sMinimum\scolumn\swith\nis\s2\sif\sthere\sis\swrapping,\sin\scase\sthere\sare\sdouble-wide\scharacters.
|
||||
D 2025-11-09T17:25:23.259
|
||||
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
|
||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||
@@ -417,7 +417,7 @@ F ext/misc/windirent.h 02211ce51f3034c675f2dbf4d228194d51b3ee05734678bad5106fff6
|
||||
F ext/misc/zipfile.c 09e6e3a3ff40a99677de3c0bc6569bd5f4709b1844ac3d1c1452a456c5a62f1c
|
||||
F ext/misc/zorder.c bddff2e1b9661a90c95c2a9a9c7ecd8908afab5763256294dd12d609d4664eee
|
||||
F ext/qrf/README.md 5011393a53bfb26b59488e5d8d8576de521058876b61318d4fe476375a4ae9a2
|
||||
F ext/qrf/qrf.c d7e7bcc6d70478002daecbd32a352f76a1de8fef2b032a73ff698bc2e0c37ffe
|
||||
F ext/qrf/qrf.c 7d3c500a73e8185a3ae097b0c47a3609ef96e0f9bc6b8b7d2f0db8c2e5330fd9
|
||||
F ext/qrf/qrf.h 49a106a7484c9761bb66bebe0043fbf43302624734a9f9734e0fa410a908e525
|
||||
F ext/rbu/rbu.c 801450b24eaf14440d8fd20385aacc751d5c9d6123398df41b1b5aa804bf4ce8
|
||||
F ext/rbu/rbu1.test 25870dd7db7eb5597e2b4d6e29e7a7e095abf332660f67d89959552ce8f8f255
|
||||
@@ -1506,7 +1506,7 @@ F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224c
|
||||
F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb
|
||||
F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc
|
||||
F test/pushdown.test 46a626ef1c0ca79b85296ff2e078b9da20a50e9b804b38f441590c3987580ddd
|
||||
F test/qrf01.test 8553f38836e3ea3320dd0ff908ee166e48ec6c1d7fc9ee81fd10c865fdc7e393
|
||||
F test/qrf01.test f229fcfe7c9907a1c0471ab2b0beed2fac01a69407d45248b490425716849603
|
||||
F test/qrf02.test 39b4afdc000bedccdafc0aecf17638df67a67aaa2d2942865ae6abcc48ba0e92
|
||||
F test/queryonly.test 5f653159e0f552f0552d43259890c1089391dcca
|
||||
F test/quick.test 1681febc928d686362d50057c642f77a02c62e57
|
||||
@@ -2173,8 +2173,8 @@ F tool/version-info.c 33d0390ef484b3b1cb685d59362be891ea162123cea181cb8e6d2cf6dd
|
||||
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
|
||||
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
|
||||
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
|
||||
P 9de3e1d3fb0b2127e983aa455cda2f38646891da65eb9ac39bb5b00d8488f52f
|
||||
R 82e4d367a67dea25cb5537608e6abc45
|
||||
P 37bd136ae842c8f8110c10b0834c804a8af133ce0caff492f37bd567a56ac6c6
|
||||
R b230166f53990d22a4280416c83ac02d
|
||||
U drh
|
||||
Z d5ab0a376a02936b9e254f6a39cd4a97
|
||||
Z 545297433252d44682281bbfa2a0dfdd
|
||||
# Remove this line to create a well-formed Fossil manifest.
|
||||
|
||||
@@ -1 +1 @@
|
||||
37bd136ae842c8f8110c10b0834c804a8af133ce0caff492f37bd567a56ac6c6
|
||||
0ee8fc00af4c82da0d597c65dd3d8590c71ea78d8f4a29653bbb21668c6c530d
|
||||
|
||||
117
test/qrf01.test
117
test/qrf01.test
@@ -550,7 +550,7 @@ do_execsql_test 5.0 {
|
||||
INSERT INTO t1 VALUES
|
||||
('entry-one',1708791504,zeroblob(300)),
|
||||
(unistr('one\u000atwo\u000athree'),1333206973,NULL),
|
||||
('sample-jsonb',1333206973,jsonb('{
|
||||
('sample-jsonb',1333101221,jsonb('{
|
||||
"alpha":53.11688723,
|
||||
"beta":"qrfWidthPrint(p, p->pOut, -p->u.sLine.mxColWth);",
|
||||
"zeta":[15,null,1333206973,"fd8ffe000104a46494600010101"]}'));
|
||||
@@ -561,20 +561,20 @@ do_test 5.1 {
|
||||
set result "\n[db format -style line -screenwidth 60 -blob sql \
|
||||
-text sql -wordwrap off -maxrowheight 77 $sql]"
|
||||
} {
|
||||
name = unistr('one\u000atwo\u000athree')
|
||||
mtime = 1333206973
|
||||
time = '2012-03-31 15:16:13'
|
||||
value =
|
||||
|
||||
name = 'sample-jsonb'
|
||||
mtime = 1333206973
|
||||
time = '2012-03-31 15:16:13'
|
||||
mtime = 1333101221
|
||||
time = '2012-03-30 09:53:41'
|
||||
value = x'cc7c57616c706861b535332e31313638383732334762657461
|
||||
c73071726657696474685072696e7428702c20702d3e704f7574
|
||||
2c202d702d3e752e734c696e652e6d78436f6c577468293b477a
|
||||
657461cb2c23313500a331333333323036393733c71b66643866
|
||||
6665303030313034613436343934363030303130313031'
|
||||
|
||||
name = unistr('one\u000atwo\u000athree')
|
||||
mtime = 1333206973
|
||||
time = '2012-03-31 15:16:13'
|
||||
value =
|
||||
|
||||
name = 'entry-one'
|
||||
mtime = 1708791504
|
||||
time = '2024-02-24 16:18:24'
|
||||
@@ -598,6 +598,13 @@ do_test 5.2 {
|
||||
-text plain -esc off -textjsonb yes \
|
||||
-wordwrap yes -maxrowheight 3 $sql]"
|
||||
} {
|
||||
name = sample-jsonb
|
||||
mtime = 1333101221
|
||||
time = 2012-03-30 09:53:41
|
||||
value = {"alpha":53.11688723,"beta":"qrfWidthPrint(p,
|
||||
p->pOut, -p->u.sLine.mxColWth);","zeta":[15,null,
|
||||
1333206973,"fd8ffe000104a46494600010101"]}
|
||||
|
||||
name = one
|
||||
two
|
||||
three
|
||||
@@ -605,13 +612,6 @@ mtime = 1333206973
|
||||
time = 2012-03-31 15:16:13
|
||||
value =
|
||||
|
||||
name = sample-jsonb
|
||||
mtime = 1333206973
|
||||
time = 2012-03-31 15:16:13
|
||||
value = {"alpha":53.11688723,"beta":"qrfWidthPrint(p,
|
||||
p->pOut, -p->u.sLine.mxColWth);","zeta":[15,null,
|
||||
1333206973,"fd8ffe000104a46494600010101"]}
|
||||
|
||||
name = entry-one
|
||||
mtime = 1708791504
|
||||
time = 2024-02-24 16:18:24
|
||||
@@ -620,5 +620,92 @@ value = x'00000000000000000000000000000000000000000000000000
|
||||
0000000000000000000000000000000000000000000000000000
|
||||
...
|
||||
}
|
||||
do_test 5.3a {
|
||||
set result "\n[db format -style box -widths {0 10 10 14}\
|
||||
-align {left right right center} \
|
||||
-blob sql \
|
||||
-text plain -esc off -textjsonb no \
|
||||
-wordwrap yes -maxrowheight 2 $sql]"
|
||||
} {
|
||||
┌──────────────┬────────────┬────────────┬────────────────┐
|
||||
│ name │ mtime │ time │ value │
|
||||
├──────────────┼────────────┼────────────┼────────────────┤
|
||||
│ sample-jsonb │ 1333101221 │ 2012-03-30 │ x'cc7c57616c70 │
|
||||
│ │ │ 09:53:41 │ 6861b535332e31 │
|
||||
│ │ │ │ ... │
|
||||
├──────────────┼────────────┼────────────┼────────────────┤
|
||||
│ one │ 1333206973 │ 2012-03-31 │ │
|
||||
│ two │ │ 15:16:13 │ │
|
||||
│ ... │ │ │ │
|
||||
├──────────────┼────────────┼────────────┼────────────────┤
|
||||
│ entry-one │ 1708791504 │ 2024-02-24 │ x'000000000000 │
|
||||
│ │ │ 16:18:24 │ 00000000000000 │
|
||||
│ │ │ │ ... │
|
||||
└──────────────┴────────────┴────────────┴────────────────┘
|
||||
}
|
||||
do_test 5.3b {
|
||||
set result "\n[db format -style table -widths {0 10 10 14}\
|
||||
-align {center right right right} \
|
||||
-blob sql \
|
||||
-text plain -esc off -textjsonb no \
|
||||
-wordwrap yes -maxrowheight 2 $sql]"
|
||||
} {
|
||||
+--------------+------------+------------+----------------+
|
||||
| name | mtime | time | value |
|
||||
+--------------+------------+------------+----------------+
|
||||
| sample-jsonb | 1333101221 | 2012-03-30 | x'cc7c57616c70 |
|
||||
| | | 09:53:41 | 6861b535332e31 |
|
||||
| | | | ... |
|
||||
+--------------+------------+------------+----------------+
|
||||
| one | 1333206973 | 2012-03-31 | |
|
||||
| two | | 15:16:13 | |
|
||||
| ... | | | |
|
||||
+--------------+------------+------------+----------------+
|
||||
| entry-one | 1708791504 | 2024-02-24 | x'000000000000 |
|
||||
| | | 16:18:24 | 00000000000000 |
|
||||
| | | | ... |
|
||||
+--------------+------------+------------+----------------+
|
||||
}
|
||||
do_test 5.3c {
|
||||
set result "\n[db format -style column -widths {0 10 10 14}\
|
||||
-align {center right right right} \
|
||||
-blob sql \
|
||||
-text plain -esc off -textjsonb no \
|
||||
-wordwrap yes -maxrowheight 2 $sql]"
|
||||
} {
|
||||
name mtime time value
|
||||
------------ ---------- ---------- --------------
|
||||
sample-jsonb 1333101221 2012-03-30 x'cc7c57616c70
|
||||
09:53:41 6861b535332e31
|
||||
...
|
||||
|
||||
one 1333206973 2012-03-31
|
||||
two 15:16:13
|
||||
...
|
||||
|
||||
entry-one 1708791504 2024-02-24 x'000000000000
|
||||
16:18:24 00000000000000
|
||||
...
|
||||
}
|
||||
do_test 5.4 {
|
||||
db eval {
|
||||
CREATE TABLE t2(a,b,c,d,e);
|
||||
WITH v(x) AS (SELECT 'abcdefghijklmnopqrstuvwxyz')
|
||||
INSERT INTO t2 SELECT x,x,x,x,x FROM v;
|
||||
}
|
||||
set sql {SELECT char(0x61,0xa,0x62,0xa,0x63,0xa,0x64) a,
|
||||
mtime b, mtime c, mtime d, mtime e FROM t1}
|
||||
set result "\n[db format -style box -widths {1 2 3 4 5}\
|
||||
-maxrowheight 3 -wordwrap off {SELECT *, 'x' AS x FROM t2}]"
|
||||
} {
|
||||
┌────┬────┬─────┬──────┬───────┬───┐
|
||||
│ a │ b │ c │ d │ e │ x │
|
||||
├────┼────┼─────┼──────┼───────┼───┤
|
||||
│ ab │ ab │ abc │ abcd │ abcde │ x │
|
||||
│ cd │ cd │ def │ efgh │ fghij │ │
|
||||
│ ef │ ef │ ghi │ ijkl │ klmno │ │
|
||||
│ .. │ .. │ ... │ ... │ ... │ │
|
||||
└────┴────┴─────┴──────┴───────┴───┘
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
||||
Reference in New Issue
Block a user