2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								package  postgres  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"fmt" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"regexp" 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-10 16:59:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"strconv" 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									"strings" 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-27 17:26:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									"time" 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									"github.com/grafana/grafana/pkg/tsdb" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								//const rsString = `(?:"([^"]*)")`;
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  rsIdentifier  =  ` ([_a-zA-Z0-9]+) `  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  sExpr  =  ` \$ `  +  rsIdentifier  +  ` \(([^\)]*)\) `  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								type  PostgresMacroEngine  struct  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									TimeRange  * tsdb . TimeRange 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-09 06:04:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									Query      * tsdb . Query 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  NewPostgresMacroEngine ( )  tsdb . SqlMacroEngine  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  & PostgresMacroEngine { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-12-09 06:04:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								func  ( m  * PostgresMacroEngine )  Interpolate ( query  * tsdb . Query ,  timeRange  * tsdb . TimeRange ,  sql  string )  ( string ,  error )  {  
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									m . TimeRange  =  timeRange 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-09 06:04:17 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
									m . Query  =  query 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									rExp ,  _  :=  regexp . Compile ( sExpr ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									var  macroError  error 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									sql  =  replaceAllStringSubmatchFunc ( rExp ,  sql ,  func ( groups  [ ] string )  string  { 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-03 02:20:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										args  :=  strings . Split ( groups [ 2 ] ,  "," ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  i ,  arg  :=  range  args  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											args [ i ]  =  strings . Trim ( arg ,  " " ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										res ,  err  :=  m . evaluateMacro ( groups [ 1 ] ,  args ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										if  err  !=  nil  &&  macroError  ==  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											macroError  =  err 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  "macro_error()" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  res 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									if  macroError  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  "" ,  macroError 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  sql ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  replaceAllStringSubmatchFunc ( re  * regexp . Regexp ,  str  string ,  repl  func ( [ ] string )  string )  string  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									result  :=  "" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									lastIndex  :=  0 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									for  _ ,  v  :=  range  re . FindAllSubmatchIndex ( [ ] byte ( str ) ,  - 1 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										groups  :=  [ ] string { } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										for  i  :=  0 ;  i  <  len ( v ) ;  i  +=  2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											groups  =  append ( groups ,  str [ v [ i ] : v [ i + 1 ] ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										result  +=  str [ lastIndex : v [ 0 ] ]  +  repl ( groups ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										lastIndex  =  v [ 1 ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									return  result  +  str [ lastIndex : ] 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								func  ( m  * PostgresMacroEngine )  evaluateMacro ( name  string ,  args  [ ] string )  ( string ,  error )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									switch  name  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  "__time" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  len ( args )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  "" ,  fmt . Errorf ( "missing time column argument for macro %v" ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  fmt . Sprintf ( "%s AS \"time\"" ,  args [ 0 ] ) ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  "__timeEpoch" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  len ( args )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  "" ,  fmt . Errorf ( "missing time column argument for macro %v" ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  fmt . Sprintf ( "extract(epoch from %s) as \"time\"" ,  args [ 0 ] ) ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									case  "__timeFilter" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  len ( args )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  "" ,  fmt . Errorf ( "missing time column argument for macro %v" ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2018-04-16 00:38:20 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										pg_version  :=  m . Query . DataSource . JsonData . Get ( "postgresVersion" ) . MustInt ( 0 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  pg_version  >=  80100  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											// postgres has to_timestamp(double) starting with 8.1
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  fmt . Sprintf ( "%s BETWEEN to_timestamp(%d) AND to_timestamp(%d)" ,  args [ 0 ] ,  m . TimeRange . GetFromAsSecondsEpoch ( ) ,  m . TimeRange . GetToAsSecondsEpoch ( ) ) ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										// dont use to_timestamp in this macro for redshift compatibility #9566
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  fmt . Sprintf ( "%s BETWEEN 'epoch'::timestamptz + %d * '1s'::interval AND 'epoch'::timestamptz + %d * '1s'::interval" ,  args [ 0 ] ,  m . TimeRange . GetFromAsSecondsEpoch ( ) ,  m . TimeRange . GetToAsSecondsEpoch ( ) ) ,  nil 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									case  "__timeFrom" : 
							 
						 
					
						
							
								
									
										
										
										
											2018-04-13 01:08:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  fmt . Sprintf ( "to_timestamp(%d)" ,  m . TimeRange . GetFromAsSecondsEpoch ( ) ) ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									case  "__timeTo" : 
							 
						 
					
						
							
								
									
										
										
										
											2018-04-13 01:08:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  fmt . Sprintf ( "to_timestamp(%d)" ,  m . TimeRange . GetToAsSecondsEpoch ( ) ) ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									case  "__timeGroup" : 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-10 16:59:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  len ( args )  <  2  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  "" ,  fmt . Errorf ( "macro %v needs time column and interval and optional fill value" ,  name ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-03 02:20:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										interval ,  err  :=  time . ParseDuration ( strings . Trim ( args [ 1 ] ,  ` ' ` ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-27 17:26:25 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  "" ,  fmt . Errorf ( "error parsing interval %v" ,  args [ 1 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-10 16:59:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										if  len ( args )  ==  3  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											m . Query . Model . Set ( "fill" ,  true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											m . Query . Model . Set ( "fillInterval" ,  interval . Seconds ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2018-03-03 02:20:30 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
											if  args [ 2 ]  ==  "NULL"  { 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-10 16:59:33 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
												m . Query . Model . Set ( "fillNull" ,  true ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											}  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												floatVal ,  err  :=  strconv . ParseFloat ( args [ 2 ] ,  64 ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												if  err  !=  nil  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
													return  "" ,  fmt . Errorf ( "error parsing fill value %v" ,  args [ 2 ] ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
												m . Query . Model . Set ( "fillValue" ,  floatVal ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2017-12-08 22:14:10 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  fmt . Sprintf ( "(extract(epoch from %s)/%v)::bigint*%v AS time" ,  args [ 0 ] ,  interval . Seconds ( ) ,  interval . Seconds ( ) ) ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									case  "__unixEpochFilter" : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										if  len ( args )  ==  0  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
											return  "" ,  fmt . Errorf ( "missing time column argument for macro %v" ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										} 
							 
						 
					
						
							
								
									
										
										
										
											2018-04-13 01:08:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  fmt . Sprintf ( "%s >= %d AND %s <= %d" ,  args [ 0 ] ,  m . TimeRange . GetFromAsSecondsEpoch ( ) ,  args [ 0 ] ,  m . TimeRange . GetToAsSecondsEpoch ( ) ) ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									case  "__unixEpochFrom" : 
							 
						 
					
						
							
								
									
										
										
										
											2018-04-13 01:08:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  fmt . Sprintf ( "%d" ,  m . TimeRange . GetFromAsSecondsEpoch ( ) ) ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									case  "__unixEpochTo" : 
							 
						 
					
						
							
								
									
										
										
										
											2018-04-13 01:08:35 +08:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
										return  fmt . Sprintf ( "%d" ,  m . TimeRange . GetToAsSecondsEpoch ( ) ) ,  nil 
							 
						 
					
						
							
								
									
										
										
										
											2017-10-10 21:19:14 +08:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
									default : 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
										return  "" ,  fmt . Errorf ( "Unknown macro %v" ,  name ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}